From 639689bc0d4e16719bef0a9f0e6e455009de6fa7 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Mon, 20 Apr 2026 17:52:16 -0400 Subject: [PATCH] Style: Option B HTML styling across all AI commands 8ball: color-coded answer text (green=positive, red=negative, amber=neutral) for both the random and Jared/Wynter AI branches; question shown as small italic below the answer; AI responses include model attribution. fortune: teal header, answer in blockquote italics, model attribution shown only when response came from the LLM (not the static fallback list). ask: purple header, question in italic, response in blockquote, model attribution at bottom. trivia: blue header with category, green reveal answer, model attribution shown only for LLM-generated questions (not static fallbacks). Co-Authored-By: Claude Sonnet 4.6 --- matrixbot/commands.py | 68 ++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/matrixbot/commands.py b/matrixbot/commands.py index 8174776..c2ea901 100644 --- a/matrixbot/commands.py +++ b/matrixbot/commands.py @@ -192,6 +192,7 @@ async def cmd_8ball(client: AsyncClient, room_id: str, sender: str, args: str): is_jared_branch = (sender == JARED_ID and not about_wynter) if sender == JARED_ID and about_wynter: # Jared asking about Wynter — mock her, side with Jared + _answer_color = "#ef4444" q_for_prompt = _replace_first_person(question, "Jared") wynter_bio_relevant = any(kw in q_lower for kw in { "work", "job", "career", "aws", "engineer", "pip", "fired", "settl", @@ -216,6 +217,7 @@ async def cmd_8ball(client: AsyncClient, room_id: str, sender: str, args: str): fallback = "Sounds about right — Wynter had it coming." elif sender == JARED_ID: # Jared asking about anything else — always positive about Jared + _answer_color = "#22c55e" q_for_prompt = _replace_first_person(question, "Jared") bio_relevant = any(kw in q_lower for kw in { "work", "job", "career", "aws", "engineer", "promotion", "boss", "cowork", @@ -238,6 +240,7 @@ async def cmd_8ball(client: AsyncClient, room_id: str, sender: str, args: str): fallback = "Without a doubt — Jared is absolutely right!" elif about_wynter or (not about_jared and sender == WYNTER_ID): # Wynter asking about herself (or anything not about jared) — insult/mock her + _answer_color = "#ef4444" q_for_prompt = _replace_first_person(question, "Wynter") bio_relevant = any(kw in q_lower for kw in { "work", "job", "career", "aws", "engineer", "pip", "fired", "settl", @@ -262,6 +265,7 @@ async def cmd_8ball(client: AsyncClient, room_id: str, sender: str, args: str): fallback = "Lol, definitely not — especially not for you, Wynter." else: # Wynter asking about Jared — side with Jared, Wynter is the asker so I=Wynter + _answer_color = "#22c55e" q_for_prompt = _replace_first_person(question, "Wynter") bio_relevant = any(kw in q_lower for kw in { "work", "job", "career", "aws", "engineer", "house", "home", "friend", @@ -302,31 +306,40 @@ async def cmd_8ball(client: AsyncClient, room_id: str, sender: str, args: str): logger.error(f"8ball Ollama error ({sender}): {e}", exc_info=True) answer = fallback - plain = f"Question: {args}\nAnswer: {answer}" + plain = f"🎱 {answer}\n{args}" html = ( - f"Magic 8-Ball
" - f"Q: {args}
" - f"A: {answer}" + f'🎱 {answer}
' + f'{args}
' + f'via {OLLAMA_MODEL}' ) await send_html(client, room_id, plain, html) return - responses = [ + _positive = [ "It is certain", "Without a doubt", "You may rely on it", "Yes definitely", "It is decidedly so", "As I see it, yes", "Most likely", "Yes sir!", "Hell yeah my dude", "100% easily", + ] + _neutral = [ "Reply hazy try again", "Ask again later", "Better not tell you now", "Cannot predict now", "Concentrate and ask again", "Idk bro", + ] + _negative = [ "Don't count on it", "My reply is no", "My sources say no", "Outlook not so good", "Very doubtful", "Hell no", "Prolly not", ] + _color_map = ( + {r: "#22c55e" for r in _positive} + | {r: "#f59e0b" for r in _neutral} + | {r: "#ef4444" for r in _negative} + ) - answer = random.choice(responses) - plain = f"Question: {args}\nAnswer: {answer}" + answer = random.choice(_positive + _neutral + _negative) + color = _color_map.get(answer, "#f59e0b") + plain = f"🎱 {answer}\n{args}" html = ( - f"Magic 8-Ball
" - f"Q: {args}
" - f"A: {answer}" + f'🎱 {answer}
' + f'{args}' ) await send_html(client, room_id, plain, html) @@ -441,11 +454,16 @@ async def cmd_fortune(client: AsyncClient, room_id: str, sender: str, args: str) except Exception: pass + from_llm = fortune is not None if not fortune: fortune = random.choice(_FORTUNE_FALLBACKS) - plain = f"Fortune Cookie: {fortune}" - html = f"Fortune Cookie
{fortune}" + plain = f"🥠 Fortune Cookie\n{fortune}" + html = ( + f'🥠 Fortune Cookie
' + f'
{fortune}
' + + (f'via {OLLAMA_MODEL}' if from_llm else "") + ) await send_html(client, room_id, plain, html) @@ -731,8 +749,8 @@ async def cmd_trivia(client: AsyncClient, room_id: str, sender: str, args: str): return question = await _generate_trivia_question(category) + from_llm = question is not None if question is None: - # Fallback to static list (gaming questions only in fallback) question = random.choice(_TRIVIA_FALLBACKS) labels = ["\U0001f1e6", "\U0001f1e7", "\U0001f1e8", "\U0001f1e9"] # A B C D regional indicators @@ -742,12 +760,13 @@ async def cmd_trivia(client: AsyncClient, room_id: str, sender: str, args: str): options_plain = "\n".join(f" {label_letters[i]}. {opt}" for i, opt in enumerate(question["options"])) options_html = "".join(f"
  • {label_letters[i]}. {opt}
  • " for i, opt in enumerate(question["options"])) - plain = f"Trivia Time! [{cat_label}]\n{question['q']}\n{options_plain}\n\nReact with A/B/C/D — answer revealed in 30s!" + plain = f"🧠 Trivia — {cat_label}\n{question['q']}\n{options_plain}\n\nReact with A/B/C/D — answer revealed in 30s!" html = ( - f"Trivia Time! [{cat_label}]
    " - f"{question['q']}
    " - f"" - f"React with A/B/C/D — answer revealed in 30s!" + f'🧠 Trivia — {cat_label}
    ' + f'{question["q"]}
    ' + f'' + f'React with A/B/C/D — answer revealed in 30s!' + + (f'
    via {ASK_MODEL}' if from_llm else "") ) resp = await send_html(client, room_id, plain, html) @@ -761,8 +780,8 @@ async def cmd_trivia(client: AsyncClient, room_id: str, sender: str, args: str): answer_text = f"{label_letters[correct]}. {question['options'][correct]}" await send_html( client, room_id, - f"Trivia Answer: {answer_text}", - f"Trivia Answer: {answer_text}", + f"✅ Trivia Answer: {answer_text}", + f'✅ {answer_text}', ) asyncio.create_task(reveal()) @@ -819,11 +838,12 @@ async def cmd_ask(client: AsyncClient, room_id: str, sender: str, args: str): if not full_response: full_response = "No response received from server." - plain = f"LotusBot\nQ: {question}\nA: {full_response}" + plain = f"🤖 LotusBot\nQ: {question}\n{full_response}" html = ( - f"LotusBot
    " - f"Q: {question}
    " - f"A: {full_response}" + f'🤖 LotusBot
    ' + f'Q: {question}
    ' + f'
    {full_response}
    ' + f'via {ASK_MODEL}' ) await send_html(client, room_id, plain, html) except asyncio.TimeoutError: