diff --git a/matrixbot/commands.py b/matrixbot/commands.py index b3aee4a..43979a0 100644 --- a/matrixbot/commands.py +++ b/matrixbot/commands.py @@ -15,13 +15,37 @@ from utils import send_text, send_html, send_reaction, sanitize_input from wordle import handle_wordle from config import ( MAX_DICE_SIDES, MAX_DICE_COUNT, BOT_PREFIX, ADMIN_USERS, - OLLAMA_URL, OLLAMA_MODEL, ASK_MODEL, COOLDOWN_SECONDS, + OLLAMA_URL, OLLAMA_MODEL, BALL_MODEL, ASK_MODEL, COOLDOWN_SECONDS, MINECRAFT_RCON_HOST, MINECRAFT_RCON_PORT, MINECRAFT_RCON_PASSWORD, RCON_TIMEOUT, MIN_USERNAME_LENGTH, MAX_USERNAME_LENGTH, ) logger = logging.getLogger("matrixbot") +# Human-readable display names for Ollama model tags +_MODEL_DISPLAY = { + "lotusllm": "Llama 3.2 1B", + "lotusllm:latest": "Llama 3.2 1B", + "lotusllmben:latest": "Llama 2 7B", + "sadiq-bd/llama3.2-1b-uncensored:latest": "Llama 3.2 1B", + "llama3.2:latest": "Llama 3.2 3B", + "llama3.2:1b": "Llama 3.2 1B", + "llama3.3:latest": "Llama 3.3 70B", + "gemma3:latest": "Gemma 3 4B", + "gemma3:1b": "Gemma 3 1B", + "huihui_ai/gemma3-abliterated:1b": "Gemma 3 1B", + "phi4-mini:latest": "Phi-4 Mini", + "deepseek-r1:latest": "DeepSeek R1", + "codellama:latest": "Code Llama 7B", + "dolphin-phi:latest": "Dolphin Phi", +} + + +def _model_label(tag: str) -> str: + """Return a friendly display name for an Ollama model tag.""" + return _MODEL_DISPLAY.get(tag, tag) + + # Registry: name -> (handler, description) COMMANDS = {} @@ -85,15 +109,27 @@ def check_cooldown(sender: str, cmd_name: str, seconds: int = COOLDOWN_SECONDS) @command("help", "Show all available commands") async def cmd_help(client: AsyncClient, room_id: str, sender: str, args: str): - lines_plain = ["Commands:"] - lines_html = ["

Commands

") - await send_html(client, room_id, "\n".join(lines_plain), "\n".join(lines_html)) + for cat_name, cmd_names in categories: + plain_lines.append(f"\n{cat_name}") + html_parts.append(f"
{cat_name}") + + await send_html(client, room_id, "\n".join(plain_lines), "".join(html_parts)) @command("ping", "Check bot latency") @@ -296,7 +332,7 @@ async def cmd_8ball(client: AsyncClient, room_id: str, sender: str, args: str): async with aiohttp.ClientSession(timeout=timeout) as session: async with session.post( f"{OLLAMA_URL}/api/generate", - json={"model": "sadiq-bd/llama3.2-1b-uncensored:latest", "prompt": prompt, "stream": False}, + json={"model": BALL_MODEL, "prompt": prompt, "stream": False}, ) as response: data = await response.json() raw = _normalize_caps(data.get("response", "").strip()) @@ -312,7 +348,7 @@ async def cmd_8ball(client: AsyncClient, room_id: str, sender: str, args: str): html = ( f'🎱 {answer}
' f'{args}
' - f'via {OLLAMA_MODEL}' + f'via {_model_label(BALL_MODEL)}' ) await send_html(client, room_id, plain, html) return @@ -424,7 +460,7 @@ _FORTUNE_FALLBACKS = [ ] -@command("fortune", "Get a fortune cookie message") +@command("fortune", "AI-generated fortune cookie") async def cmd_fortune(client: AsyncClient, room_id: str, sender: str, args: str): fortune = None try: @@ -464,7 +500,7 @@ async def cmd_fortune(client: AsyncClient, room_id: str, sender: str, args: str) html = ( f'🥠 Fortune Cookie
' f'
{fortune}
' - + (f'via {OLLAMA_MODEL}' if from_llm else "") + + (f'via {_model_label(OLLAMA_MODEL)}' if from_llm else "") ) await send_html(client, room_id, plain, html) @@ -768,7 +804,7 @@ async def cmd_trivia(client: AsyncClient, room_id: str, sender: str, args: str): f'{question["q"]}
' f'' f'React with A/B/C/D — answer revealed in 30s!' - + (f'
via {ASK_MODEL}' if from_llm else "") + + (f'
via {_model_label(ASK_MODEL)}' if from_llm else "") ) resp = await send_html(client, room_id, plain, html) @@ -792,7 +828,7 @@ async def cmd_trivia(client: AsyncClient, room_id: str, sender: str, args: str): # ==================== INTEGRATIONS ==================== -@command("ask", "Ask Lotus LLM a question (2min cooldown)") +@command("ask", "Ask LotusBot a question (2min cooldown)") async def cmd_ask(client: AsyncClient, room_id: str, sender: str, args: str): if not args: await send_text(client, room_id, f"Usage: {BOT_PREFIX}ask ") @@ -845,7 +881,7 @@ async def cmd_ask(client: AsyncClient, room_id: str, sender: str, args: str): f'🤖 LotusBot
' f'Q: {question}
' f'
{full_response}
' - f'via {ASK_MODEL}' + f'via {_model_label(ASK_MODEL)}' ) await send_html(client, room_id, plain, html) except asyncio.TimeoutError: @@ -907,7 +943,7 @@ async def cmd_minecraft(client: AsyncClient, room_id: str, sender: str, args: st # ==================== ADMIN COMMANDS ==================== -@command("health", "Bot status and health (admin only)") +@command("health", "Bot health & stats (admin only)") async def cmd_health(client: AsyncClient, room_id: str, sender: str, args: str): if sender not in ADMIN_USERS: await send_text(client, room_id, "You don't have permission to use this command.") diff --git a/matrixbot/config.py b/matrixbot/config.py index 499dea8..24518ab 100644 --- a/matrixbot/config.py +++ b/matrixbot/config.py @@ -18,7 +18,8 @@ LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO") # Integrations OLLAMA_URL = os.getenv("OLLAMA_URL", "http://10.10.10.157:11434") -OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "lotusllm") +OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "llama3.2:latest") +BALL_MODEL = os.getenv("BALL_MODEL", "sadiq-bd/llama3.2-1b-uncensored:latest") ASK_MODEL = os.getenv("ASK_MODEL", "gemma3:latest") MINECRAFT_RCON_HOST = os.getenv("MINECRAFT_RCON_HOST", "10.10.10.67") MINECRAFT_RCON_PORT = int(os.getenv("MINECRAFT_RCON_PORT", "25575"))