From ca541c2e828ea3c1e03ce06db89dd598c8385c2a Mon Sep 17 00:00:00 2001 From: Kingston-SCYD Date: Sun, 16 Aug 2026 23:07:29 -0500 Subject: [PATCH] Fix API URL (api.greenpt.ai), add models command, remove debug logging --- assistant/assistant.py | 101 +++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 13 deletions(-) diff --git a/assistant/assistant.py b/assistant/assistant.py index 31e8332..2890ba5 100644 --- a/assistant/assistant.py +++ b/assistant/assistant.py @@ -1,11 +1,8 @@ -import logging import aiohttp import discord from redbot.core import commands, Config, checks from redbot.core.bot import Red -log = logging.getLogger("red.assistant") - class APIKeyModal(discord.ui.Modal): def __init__(self, config): @@ -38,7 +35,7 @@ class APIKeyButton(discord.ui.View): class Assistant(commands.Cog): """AI chatbot assistant. Set a chat channel or get responses when the bot is pinged.""" - BASE_URL = "https://greenpt.com/v1" + BASE_URL = "https://api.greenpt.ai/v1" def __init__(self, bot: Red): self.bot = bot @@ -75,19 +72,12 @@ class Assistant(commands.Cog): guild = message.guild - if self.bot.user in message.mentions: - log.info("[ASSISTANT DEBUG] Mention detected from %s in #%s", message.author, message.channel) - enabled = await self.config.guild(guild).enabled() if not enabled: - if self.bot.user in message.mentions: - log.info("[ASSISTANT DEBUG] Guild %s is disabled", guild.id) return api_key = await self.config.api_key() if not api_key: - if self.bot.user in message.mentions: - log.info("[ASSISTANT DEBUG] No API key set") return chat_channel_id = await self.config.guild(guild).chat_channel() @@ -99,8 +89,6 @@ class Assistant(commands.Cog): if not is_chat_channel and not is_ping: return - log.info("[ASSISTANT DEBUG] Processing message, is_ping=%s, is_chat_channel=%s", is_ping, is_chat_channel) - content = message.content if is_ping: for mention in (f"<@{self.bot.user.id}>", f"<@!{self.bot.user.id}>"): @@ -225,6 +213,93 @@ class Assistant(commands.Cog): await self.config.guild(ctx.guild).model.set(model) await ctx.send(f"Model set to **{model}**.") + @assistant.command(name="models") + async def assistant_models(self, ctx: commands.Context): + """List available models sorted by cost (cheapest first).""" + # Pricing per 1M tokens (EUR) from GreenPT docs + MODEL_PRICING = { + "deepseek-v4-flash-0731": {"input": 0.14, "output": 0.35}, + "minimax-m2.5": {"input": 0.17, "output": 0.99}, + "mistral-small-3.2-24b-instruct-2506": {"input": 0.20, "output": 0.40}, + "gpt-oss-120b": {"input": 0.20, "output": 0.70}, + "voxtral-small-24b-2507": {"input": 0.20, "output": 0.45}, + "green-l": {"input": 0.25, "output": 0.80}, + "green-l-raw": {"input": 0.25, "output": 0.80}, + "qwen3-coder-30b-a3b-instruct": {"input": 0.25, "output": 0.95}, + "gemma-3-27b-it": {"input": 0.30, "output": 0.60}, + "qwen3.6-35b-a3b": {"input": 0.30, "output": 1.80}, + "green-r": {"input": 0.35, "output": 0.95}, + "green-r-raw": {"input": 0.35, "output": 0.95}, + "gemma4": {"input": 0.50, "output": 1.50}, + "devstral-2-123b-instruct-2512": {"input": 0.50, "output": 2.40}, + "kimi-k2.6": {"input": 0.66, "output": 3.75}, + "qwen3.5-397b-a17b": {"input": 0.70, "output": 4.35}, + "kimi-k2.7-code": {"input": 0.79, "output": 3.85}, + "qwen3-235b-a22b-instruct-2507": {"input": 0.90, "output": 2.70}, + "glm-5.2": {"input": 1.10, "output": 4.40}, + "llama-3.3-70b-instruct": {"input": 1.10, "output": 1.10}, + "mistral-medium-3.5-128b": {"input": 1.80, "output": 9.00}, + "kimi-k3": {"input": 3.30, "output": 16.50}, + } + + api_key = await self.config.api_key() + if not api_key or not self.session: + await ctx.send("API key not set. Use `[p]assistant setkey` first.") + return + + # Fetch live model list from API + try: + async with self.session.get( + f"{self.BASE_URL}/models", + headers={"Authorization": f"Bearer {api_key}"}, + timeout=aiohttp.ClientTimeout(total=15), + ) as resp: + if resp.status != 200: + await ctx.send(f"Failed to fetch models (HTTP {resp.status}).") + return + data = await resp.json() + except Exception as exc: + await ctx.send(f"Request failed: {exc}") + return + + models = data.get("data", []) + if not models: + await ctx.send("No models returned by the API.") + return + + # Build list with pricing, sorted by combined cost (input + output) + current_model = await self.config.guild(ctx.guild).model() + lines = [] + model_entries = [] + for m in models: + model_id = m["id"] + pricing = MODEL_PRICING.get(model_id) + if pricing: + total = pricing["input"] + pricing["output"] + model_entries.append((total, model_id, pricing)) + else: + # Unknown pricing, put at the end + model_entries.append((9999, model_id, None)) + + model_entries.sort(key=lambda x: x[0]) + + for total, model_id, pricing in model_entries: + marker = " ◀" if model_id == current_model else "" + if pricing: + lines.append( + f"`{model_id}` — €{pricing['input']:.2f} in / €{pricing['output']:.2f} out{marker}" + ) + else: + lines.append(f"`{model_id}` — pricing unknown{marker}") + + embed = discord.Embed( + title="Available Models (cheapest first)", + description="\n".join(lines), + color=await ctx.embed_color(), + ) + embed.set_footer(text="Prices in EUR per 1M tokens. ◀ = current model.") + await ctx.send(embed=embed) + @assistant.command(name="temp") async def assistant_temp(self, ctx: commands.Context, temperature: float): """Set the temperature (0.0 - 2.0)."""