Fix API URL (api.greenpt.ai), add models command, remove debug logging
This commit is contained in:
+88
-13
@@ -1,11 +1,8 @@
|
|||||||
import logging
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import discord
|
import discord
|
||||||
from redbot.core import commands, Config, checks
|
from redbot.core import commands, Config, checks
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
|
|
||||||
log = logging.getLogger("red.assistant")
|
|
||||||
|
|
||||||
|
|
||||||
class APIKeyModal(discord.ui.Modal):
|
class APIKeyModal(discord.ui.Modal):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
@@ -38,7 +35,7 @@ class APIKeyButton(discord.ui.View):
|
|||||||
class Assistant(commands.Cog):
|
class Assistant(commands.Cog):
|
||||||
"""AI chatbot assistant. Set a chat channel or get responses when the bot is pinged."""
|
"""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):
|
def __init__(self, bot: Red):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
@@ -75,19 +72,12 @@ class Assistant(commands.Cog):
|
|||||||
|
|
||||||
guild = message.guild
|
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()
|
enabled = await self.config.guild(guild).enabled()
|
||||||
if not enabled:
|
if not enabled:
|
||||||
if self.bot.user in message.mentions:
|
|
||||||
log.info("[ASSISTANT DEBUG] Guild %s is disabled", guild.id)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
api_key = await self.config.api_key()
|
api_key = await self.config.api_key()
|
||||||
if not api_key:
|
if not api_key:
|
||||||
if self.bot.user in message.mentions:
|
|
||||||
log.info("[ASSISTANT DEBUG] No API key set")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
chat_channel_id = await self.config.guild(guild).chat_channel()
|
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:
|
if not is_chat_channel and not is_ping:
|
||||||
return
|
return
|
||||||
|
|
||||||
log.info("[ASSISTANT DEBUG] Processing message, is_ping=%s, is_chat_channel=%s", is_ping, is_chat_channel)
|
|
||||||
|
|
||||||
content = message.content
|
content = message.content
|
||||||
if is_ping:
|
if is_ping:
|
||||||
for mention in (f"<@{self.bot.user.id}>", f"<@!{self.bot.user.id}>"):
|
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 self.config.guild(ctx.guild).model.set(model)
|
||||||
await ctx.send(f"Model set to **{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")
|
@assistant.command(name="temp")
|
||||||
async def assistant_temp(self, ctx: commands.Context, temperature: float):
|
async def assistant_temp(self, ctx: commands.Context, temperature: float):
|
||||||
"""Set the temperature (0.0 - 2.0)."""
|
"""Set the temperature (0.0 - 2.0)."""
|
||||||
|
|||||||
Reference in New Issue
Block a user