diff --git a/bot/routes/bipolar_mode.py b/bot/routes/bipolar_mode.py index dc1a406..fa2a687 100644 --- a/bot/routes/bipolar_mode.py +++ b/bot/routes/bipolar_mode.py @@ -129,7 +129,7 @@ def trigger_argument(data: BipolarTriggerRequest): if message_id: async def trigger_from_message(): success, error = await force_trigger_argument_from_message_id( - channel_id, message_id, globals.client, data.context + channel_id, message_id, globals.client, data.context, topic=data.topic ) if not success: logger.error(f"Failed to trigger argument from message: {error}") @@ -148,8 +148,8 @@ def trigger_argument(data: BipolarTriggerRequest): if not channel: return JSONResponse(status_code=404, content={"status": "error", "message": f"Channel {channel_id} not found"}) - # Trigger the argument - globals.client.loop.create_task(force_trigger_argument(channel, globals.client, data.context)) + # Trigger the argument with optional custom topic + globals.client.loop.create_task(force_trigger_argument(channel, globals.client, data.context, topic=data.topic)) return { "status": "ok", diff --git a/bot/routes/models.py b/bot/routes/models.py index d203900..f49e018 100644 --- a/bot/routes/models.py +++ b/bot/routes/models.py @@ -46,6 +46,7 @@ class BipolarTriggerRequest(BaseModel): channel_id: str # String to handle large Discord IDs from JS message_id: str = None # Optional: starting message ID (string) context: str = "" + topic: str = "" # Optional: custom argument topic (overrides random topic selection) class ManualCropRequest(BaseModel): diff --git a/bot/static/index.html b/bot/static/index.html index c928e66..acfa907 100644 --- a/bot/static/index.html +++ b/bot/static/index.html @@ -238,6 +238,14 @@ +
+ + +
+ Leave blank for random topic selection. Enter a custom theme to frame the argument uniquely. +
+
+ diff --git a/bot/static/js/modes.js b/bot/static/js/modes.js index 7bc8f13..0c803c0 100644 --- a/bot/static/js/modes.js +++ b/bot/static/js/modes.js @@ -249,6 +249,7 @@ async function triggerBipolarArgument() { const channelIdInput = document.getElementById('bipolar-channel-id').value.trim(); const messageIdInput = document.getElementById('bipolar-message-id').value.trim(); const context = document.getElementById('bipolar-context').value; + const topic = document.getElementById('bipolar-topic').value.trim(); const statusDiv = document.getElementById('bipolar-status'); if (!channelIdInput) { @@ -278,6 +279,10 @@ async function triggerBipolarArgument() { requestBody.message_id = messageIdInput; } + if (topic) { + requestBody.topic = topic; + } + const result = await apiCall('/bipolar-mode/trigger-argument', 'POST', requestBody); if (result.status === 'error') { @@ -290,6 +295,7 @@ async function triggerBipolarArgument() { showNotification(`⚔️ Argument triggered!`); document.getElementById('bipolar-context').value = ''; + document.getElementById('bipolar-topic').value = ''; document.getElementById('bipolar-message-id').value = ''; loadActiveArguments(); diff --git a/bot/utils/bipolar_mode.py b/bot/utils/bipolar_mode.py index a1f0043..3589c38 100644 --- a/bot/utils/bipolar_mode.py +++ b/bot/utils/bipolar_mode.py @@ -1175,7 +1175,7 @@ def should_end_argument(channel_id: int) -> tuple: return False, None -async def run_argument(channel: discord.TextChannel, client, trigger_context: str = "", starting_message: discord.Message = None): +async def run_argument(channel: discord.TextChannel, client, trigger_context: str = "", starting_message: discord.Message = None, argument_topic: str = None): """Run a full argument event between both Mikus Args: @@ -1184,6 +1184,9 @@ async def run_argument(channel: discord.TextChannel, client, trigger_context: st trigger_context: Optional context about what triggered the argument starting_message: Optional message to use as the first message in the argument (the opposite persona will respond to it) + argument_topic: Optional custom topic string. If provided, overrides the + random topic selection. Pass empty string to force no topic. + Pass None (default) to use random topic selection. """ from utils.llm import query_llama from utils.conversation_history import conversation_history @@ -1225,8 +1228,19 @@ async def run_argument(channel: discord.TextChannel, client, trigger_context: st conversation_log = [] try: - # Pick a dynamic argument topic to give this argument a unique framing - argument_topic = pick_argument_topic(channel_id) + # Pick a dynamic argument topic to give this argument a unique framing. + # If caller provided a custom topic, use it instead of random selection. + # If caller passed empty string, use no topic (no theme guidance). + if argument_topic is None: + # Default: random weighted selection from rotation system + argument_topic = pick_argument_topic(channel_id) + elif argument_topic == "": + # Explicitly no topic — skip theme guidance entirely + argument_topic = "" + logger.info(f"No argument topic requested for channel {channel_id}") + else: + # Custom topic from caller (e.g. Web UI field) + logger.info(f"Using custom argument topic for channel {channel_id}: '{argument_topic[:80]}...'") # If no starting message, generate the initial interrupting message if last_message is None: @@ -1524,7 +1538,7 @@ async def maybe_trigger_argument(channel: discord.TextChannel, client, context: return False -async def force_trigger_argument(channel: discord.TextChannel, client, context: str = "", starting_message: discord.Message = None): +async def force_trigger_argument(channel: discord.TextChannel, client, context: str = "", starting_message: discord.Message = None, topic: str = None): """Force trigger an argument (for manual triggers) Args: @@ -1532,6 +1546,7 @@ async def force_trigger_argument(channel: discord.TextChannel, client, context: client: Discord client context: Optional context string starting_message: Optional message to use as the first message in the argument + topic: Optional custom argument topic. None = random, "" = no topic, str = custom. """ if not globals.BIPOLAR_MODE: logger.warning("Cannot trigger argument - bipolar mode is not enabled") @@ -1541,11 +1556,11 @@ async def force_trigger_argument(channel: discord.TextChannel, client, context: logger.warning("Argument already in progress in this channel") return False - create_tracked_task(run_argument(channel, client, context, starting_message), task_name="bipolar_argument_forced") + create_tracked_task(run_argument(channel, client, context, starting_message, argument_topic=topic), task_name="bipolar_argument_forced") return True -async def force_trigger_argument_from_message_id(channel_id: int, message_id: int, client, context: str = ""): +async def force_trigger_argument_from_message_id(channel_id: int, message_id: int, client, context: str = "", topic: str = None): """Force trigger an argument starting from a specific message ID Args: @@ -1579,5 +1594,5 @@ async def force_trigger_argument_from_message_id(channel_id: int, message_id: in return False, f"Failed to fetch message: {str(e)}" # Trigger the argument with this message as starting point - create_tracked_task(run_argument(channel, client, context, message), task_name="bipolar_argument_from_msg") + create_tracked_task(run_argument(channel, client, context, message, argument_topic=topic), task_name="bipolar_argument_from_msg") return True, None