Rename greeptchat cog to assistant - generic AI chatbot branding
This commit is contained in:
@@ -17,6 +17,13 @@ Homepage: https://homepage.kingstons-scrapyard.net/
|
|||||||
- [Permissions Required](#permissions-required)
|
- [Permissions Required](#permissions-required)
|
||||||
- [Scrapyard Cogworks Modifications](#scrapyard-cogworks-modifications)
|
- [Scrapyard Cogworks Modifications](#scrapyard-cogworks-modifications)
|
||||||
|
|
||||||
|
**Assistant**
|
||||||
|
- [Assistant](#assistant)
|
||||||
|
- [Assistant Installation](#assistant-installation)
|
||||||
|
- [Assistant User Commands](#assistant-user-commands)
|
||||||
|
- [Assistant Admin/Owner Commands](#assistant-adminowner-commands)
|
||||||
|
- [Assistant Behavior](#assistant-behavior)
|
||||||
|
|
||||||
**TtsToy**
|
**TtsToy**
|
||||||
- [TtsToy](#ttstoy)
|
- [TtsToy](#ttstoy)
|
||||||
- [TtsToy User Commands](#user-commands-1)
|
- [TtsToy User Commands](#user-commands-1)
|
||||||
@@ -560,6 +567,173 @@ The `[p]autoroom allow` command now accepts multiple users/roles in a single com
|
|||||||
---
|
---
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# Assistant
|
||||||
|
|
||||||
|
AI chatbot cog that responds in a dedicated channel or when the bot is @mentioned. Uses an OpenAI-compatible API backend. Designed for fun, unpredictable responses — crank the temperature and give it a wild system prompt.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- **Chat channel mode** — set a channel where the bot responds to every message
|
||||||
|
- **Ping mode** — responds when @mentioned in any channel
|
||||||
|
- **Custom system prompt** — control the bot's personality
|
||||||
|
- **Temperature control** — turn it up for chaotic/funny responses
|
||||||
|
- **Question mode** — optionally restrict responses to messages ending with `?`
|
||||||
|
- **Conversation history** — remembers the last 20 messages per channel (in memory only)
|
||||||
|
- **Long response handling** — automatically chunks replies over 2000 characters
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Python 3.11+
|
||||||
|
- Red-DiscordBot 3.5.0+
|
||||||
|
- Dependencies: `aiohttp`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Assistant Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
[p]cog install scrapyard assistant
|
||||||
|
[p]load assistant
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Assistant User Commands
|
||||||
|
|
||||||
|
The assistant responds automatically in the configured chat channel or when pinged. There are no user-invoked "chat" commands — just talk to it.
|
||||||
|
|
||||||
|
**In the chat channel:** Send any message and the bot replies.
|
||||||
|
|
||||||
|
**Anywhere else:** @mention the bot with your message.
|
||||||
|
|
||||||
|
```
|
||||||
|
@Bot what's the meaning of life?
|
||||||
|
```
|
||||||
|
|
||||||
|
If **question mode** is on, messages must end with `?` or they'll be ignored.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Assistant Admin/Owner Commands
|
||||||
|
|
||||||
|
All commands are under the `[p]assistant` group.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant setkey`
|
||||||
|
|
||||||
|
**Requires:** Bot Owner
|
||||||
|
|
||||||
|
Set the API key via a private modal dialog. The key is stored globally (shared across all servers the bot is in).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant toggle`
|
||||||
|
|
||||||
|
Toggle the assistant on or off for the current server. Enabled by default.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant channel [#channel]`
|
||||||
|
|
||||||
|
Set the dedicated chat channel where the bot responds to all messages.
|
||||||
|
|
||||||
|
- With a channel: sets that channel as the chat channel.
|
||||||
|
- Without a channel: clears the setting (bot only responds to @mentions).
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```
|
||||||
|
[p]assistant channel #bot-chat
|
||||||
|
[p]assistant channel
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant model <model>`
|
||||||
|
|
||||||
|
Set the AI model to use.
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```
|
||||||
|
[p]assistant model gemma4
|
||||||
|
[p]assistant model green-l
|
||||||
|
[p]assistant model green-r
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant temp <temperature>`
|
||||||
|
|
||||||
|
Set the response temperature.
|
||||||
|
|
||||||
|
- Range: `0.0` to `2.0`
|
||||||
|
- Lower values (0.1–0.5) = focused, predictable responses
|
||||||
|
- Higher values (1.2–2.0) = creative, chaotic, funny responses
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```
|
||||||
|
[p]assistant temp 0.3
|
||||||
|
[p]assistant temp 1.8
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant system <prompt>`
|
||||||
|
|
||||||
|
Set the system prompt that defines the bot's personality and behavior.
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
```
|
||||||
|
[p]assistant system You are a helpful assistant.
|
||||||
|
[p]assistant system You are an unhinged gremlin who gives terrible life advice in the style of a 90s infomercial host. Everything is an emergency.
|
||||||
|
[p]assistant system You are a pirate who only speaks in nautical metaphors and refuses to acknowledge anything invented after 1750.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant question`
|
||||||
|
|
||||||
|
Toggle question mode. When ON, the bot only responds to messages that end with `?`. Everything else is ignored.
|
||||||
|
|
||||||
|
This is a toggle — run again to disable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant clear`
|
||||||
|
|
||||||
|
Clear the conversation history for the current channel. The bot will forget all previous context.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `[p]assistant settings`
|
||||||
|
|
||||||
|
Display the current configuration as an embed:
|
||||||
|
|
||||||
|
- Enabled (yes/no)
|
||||||
|
- Chat Channel
|
||||||
|
- API Key (set/not set)
|
||||||
|
- Model
|
||||||
|
- Temperature
|
||||||
|
- Question Mode (on/off)
|
||||||
|
- System Prompt (first 200 chars)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Assistant Behavior
|
||||||
|
|
||||||
|
- **History:** The bot keeps the last 20 messages (user + assistant) per channel in memory. History is lost on cog reload/bot restart.
|
||||||
|
- **Typing indicator:** The bot shows "typing..." while waiting for the API response.
|
||||||
|
- **Long responses:** Replies over 2000 characters are split into multiple messages.
|
||||||
|
- **Error handling:** If the API is down or returns an error, the bot replies with the error info.
|
||||||
|
- **No response to bots:** The assistant ignores messages from other bots.
|
||||||
|
- **Per-guild settings:** Model, temperature, system prompt, channel, and question mode are all configured per server.
|
||||||
|
- **Global API key:** The API key is set once by the bot owner and applies to all servers.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
---
|
||||||
|
---
|
||||||
|
|
||||||
# TtsToy
|
# TtsToy
|
||||||
|
|
||||||
Multi-engine text-to-speech cog with voice cloning, emoji-triggered sound effects, inline voice switching, a TTS queue system, and a companion web UI. Plays audio in voice channels and uploads MP3 files to chat.
|
Multi-engine text-to-speech cog with voice cloning, emoji-triggered sound effects, inline voice switching, a TTS queue system, and a companion web UI. Plays audio in voice channels and uploads MP3 files to chat.
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from .assistant import Assistant
|
||||||
|
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Assistant(bot))
|
||||||
@@ -6,12 +6,12 @@ from redbot.core.bot import Red
|
|||||||
|
|
||||||
class APIKeyModal(discord.ui.Modal):
|
class APIKeyModal(discord.ui.Modal):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super().__init__(title="GreenPT API Key")
|
super().__init__(title="API Key")
|
||||||
self.config = config
|
self.config = config
|
||||||
self.key_input = discord.ui.TextInput(
|
self.key_input = discord.ui.TextInput(
|
||||||
label="API Key",
|
label="API Key",
|
||||||
style=discord.TextStyle.short,
|
style=discord.TextStyle.short,
|
||||||
placeholder="Paste your GreenPT API key here",
|
placeholder="Paste your API key here",
|
||||||
required=True,
|
required=True,
|
||||||
)
|
)
|
||||||
self.add_item(self.key_input)
|
self.add_item(self.key_input)
|
||||||
@@ -21,8 +21,8 @@ class APIKeyModal(discord.ui.Modal):
|
|||||||
await interaction.response.send_message("API key saved.", ephemeral=True)
|
await interaction.response.send_message("API key saved.", ephemeral=True)
|
||||||
|
|
||||||
|
|
||||||
class GreeptChat(commands.Cog):
|
class Assistant(commands.Cog):
|
||||||
"""AI chat via the GreenPT API. Set a chat channel or get responses when 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://greenpt.com/v1"
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ class GreeptChat(commands.Cog):
|
|||||||
reply = await self._chat(guild, message.channel.id, content)
|
reply = await self._chat(guild, message.channel.id, content)
|
||||||
|
|
||||||
if reply is None:
|
if reply is None:
|
||||||
await message.reply("No response from GreenPT.")
|
await message.reply("No response from the assistant.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if len(reply) <= 2000:
|
if len(reply) <= 2000:
|
||||||
@@ -167,24 +167,24 @@ class GreeptChat(commands.Cog):
|
|||||||
# Commands
|
# Commands
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
greept = commands.Group("greept", "GreenPT chat settings.", guild_only=True)
|
assistant = commands.Group("assistant", "AI assistant settings.", guild_only=True)
|
||||||
|
|
||||||
@greept.command(name="setkey")
|
@assistant.command(name="setkey")
|
||||||
@checks.is_owner()
|
@checks.is_owner()
|
||||||
async def greept_setkey(self, ctx: commands.Context):
|
async def assistant_setkey(self, ctx: commands.Context):
|
||||||
"""Set the GreenPT API key (opens a private modal)."""
|
"""Set the API key (opens a private modal)."""
|
||||||
await ctx.send_modal(APIKeyModal(self.config))
|
await ctx.send_modal(APIKeyModal(self.config))
|
||||||
|
|
||||||
@greept.command(name="toggle")
|
@assistant.command(name="toggle")
|
||||||
async def greept_toggle(self, ctx: commands.Context):
|
async def assistant_toggle(self, ctx: commands.Context):
|
||||||
"""Toggle the cog on or off for this server."""
|
"""Toggle the assistant on or off for this server."""
|
||||||
current = await self.config.guild(ctx.guild).enabled()
|
current = await self.config.guild(ctx.guild).enabled()
|
||||||
await self.config.guild(ctx.guild).enabled.set(not current)
|
await self.config.guild(ctx.guild).enabled.set(not current)
|
||||||
state = "enabled" if not current else "disabled"
|
state = "enabled" if not current else "disabled"
|
||||||
await ctx.send(f"GreeptChat **{state}** for this server.")
|
await ctx.send(f"Assistant **{state}** for this server.")
|
||||||
|
|
||||||
@greept.command(name="channel")
|
@assistant.command(name="channel")
|
||||||
async def greept_channel(self, ctx: commands.Context, channel: discord.TextChannel | None = None):
|
async def assistant_channel(self, ctx: commands.Context, channel: discord.TextChannel | None = None):
|
||||||
"""Set the dedicated chat channel. Omit to clear."""
|
"""Set the dedicated chat channel. Omit to clear."""
|
||||||
if channel is None:
|
if channel is None:
|
||||||
await self.config.guild(ctx.guild).chat_channel.set(None)
|
await self.config.guild(ctx.guild).chat_channel.set(None)
|
||||||
@@ -193,14 +193,14 @@ class GreeptChat(commands.Cog):
|
|||||||
await self.config.guild(ctx.guild).chat_channel.set(channel.id)
|
await self.config.guild(ctx.guild).chat_channel.set(channel.id)
|
||||||
await ctx.send(f"Chat channel set to {channel.mention}.")
|
await ctx.send(f"Chat channel set to {channel.mention}.")
|
||||||
|
|
||||||
@greept.command(name="model")
|
@assistant.command(name="model")
|
||||||
async def greept_model(self, ctx: commands.Context, model: str):
|
async def assistant_model(self, ctx: commands.Context, model: str):
|
||||||
"""Set the model (e.g. gemma4, green-l, green-r)."""
|
"""Set the model (e.g. gemma4, green-l, green-r)."""
|
||||||
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}**.")
|
||||||
|
|
||||||
@greept.command(name="temp")
|
@assistant.command(name="temp")
|
||||||
async def greept_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)."""
|
||||||
if not 0.0 <= temperature <= 2.0:
|
if not 0.0 <= temperature <= 2.0:
|
||||||
await ctx.send("Must be between 0.0 and 2.0.")
|
await ctx.send("Must be between 0.0 and 2.0.")
|
||||||
@@ -208,29 +208,29 @@ class GreeptChat(commands.Cog):
|
|||||||
await self.config.guild(ctx.guild).temperature.set(temperature)
|
await self.config.guild(ctx.guild).temperature.set(temperature)
|
||||||
await ctx.send(f"Temperature set to **{temperature}**.")
|
await ctx.send(f"Temperature set to **{temperature}**.")
|
||||||
|
|
||||||
@greept.command(name="system")
|
@assistant.command(name="system")
|
||||||
async def greept_system(self, ctx: commands.Context, *, prompt: str):
|
async def assistant_system(self, ctx: commands.Context, *, prompt: str):
|
||||||
"""Set the system prompt."""
|
"""Set the system prompt."""
|
||||||
await self.config.guild(ctx.guild).system_prompt.set(prompt)
|
await self.config.guild(ctx.guild).system_prompt.set(prompt)
|
||||||
await ctx.send("System prompt updated.")
|
await ctx.send("System prompt updated.")
|
||||||
|
|
||||||
@greept.command(name="question")
|
@assistant.command(name="question")
|
||||||
async def greept_question(self, ctx: commands.Context):
|
async def assistant_question(self, ctx: commands.Context):
|
||||||
"""Toggle question mode (messages must end with ?)."""
|
"""Toggle question mode (messages must end with ?)."""
|
||||||
current = await self.config.guild(ctx.guild).question_mode()
|
current = await self.config.guild(ctx.guild).question_mode()
|
||||||
await self.config.guild(ctx.guild).question_mode.set(not current)
|
await self.config.guild(ctx.guild).question_mode.set(not current)
|
||||||
state = "ON" if not current else "OFF"
|
state = "ON" if not current else "OFF"
|
||||||
await ctx.send(f"Question mode **{state}**.")
|
await ctx.send(f"Question mode **{state}**.")
|
||||||
|
|
||||||
@greept.command(name="clear")
|
@assistant.command(name="clear")
|
||||||
async def greept_clear(self, ctx: commands.Context):
|
async def assistant_clear(self, ctx: commands.Context):
|
||||||
"""Clear conversation history for this channel."""
|
"""Clear conversation history for this channel."""
|
||||||
key = (ctx.guild.id, ctx.channel.id)
|
key = (ctx.guild.id, ctx.channel.id)
|
||||||
self.history.pop(key, None)
|
self.history.pop(key, None)
|
||||||
await ctx.send("History cleared for this channel.")
|
await ctx.send("History cleared for this channel.")
|
||||||
|
|
||||||
@greept.command(name="settings")
|
@assistant.command(name="settings")
|
||||||
async def greept_settings(self, ctx: commands.Context):
|
async def assistant_settings(self, ctx: commands.Context):
|
||||||
"""Show current settings."""
|
"""Show current settings."""
|
||||||
cfg = self.config.guild(ctx.guild)
|
cfg = self.config.guild(ctx.guild)
|
||||||
enabled = await cfg.enabled()
|
enabled = await cfg.enabled()
|
||||||
@@ -243,7 +243,7 @@ class GreeptChat(commands.Cog):
|
|||||||
|
|
||||||
channel_str = f"<#{chat_channel}>" if chat_channel else "None"
|
channel_str = f"<#{chat_channel}>" if chat_channel else "None"
|
||||||
|
|
||||||
embed = discord.Embed(title="GreeptChat Settings", color=await ctx.embed_color())
|
embed = discord.Embed(title="Assistant Settings", color=await ctx.embed_color())
|
||||||
embed.add_field(name="Enabled", value=str(enabled), inline=True)
|
embed.add_field(name="Enabled", value=str(enabled), inline=True)
|
||||||
embed.add_field(name="Chat Channel", value=channel_str, inline=True)
|
embed.add_field(name="Chat Channel", value=channel_str, inline=True)
|
||||||
embed.add_field(name="API Key", value="Set" if has_key else "Not set", inline=True)
|
embed.add_field(name="API Key", value="Set" if has_key else "Not set", inline=True)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"author": ["Scrapyard Cogworks"],
|
||||||
|
"install_msg": "Assistant cog installed. Use [p]assistant to configure.",
|
||||||
|
"name": "Assistant",
|
||||||
|
"short": "AI chatbot assistant with channel and ping modes.",
|
||||||
|
"description": "AI chatbot assistant using an OpenAI-compatible API. Set a dedicated chat channel or get responses when the bot is pinged. Supports temperature, model, system prompt, and question mode.",
|
||||||
|
"tags": ["ai", "chat", "assistant", "gpt", "llm"],
|
||||||
|
"requirements": ["aiohttp"],
|
||||||
|
"min_bot_version": "3.5.0",
|
||||||
|
"end_user_data_statement": "This cog stores conversation history per channel in memory only."
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
from .greeptchat import GreeptChat
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot):
|
|
||||||
await bot.add_cog(GreeptChat(bot))
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"author": ["Scrapyard Cogworks"],
|
|
||||||
"install_msg": "GreeptChat cog installed. Use [p]greept to configure.",
|
|
||||||
"name": "GreeptChat",
|
|
||||||
"short": "AI chat via GreenPT API with channel and ping modes.",
|
|
||||||
"description": "Connects to the GreenPT OpenAI-compatible API for AI chat. Set a dedicated chat channel or get responses when the bot is pinged. Supports temperature, model, system prompt, and question mode.",
|
|
||||||
"tags": ["ai", "chat", "greenpt", "gpt", "llm"],
|
|
||||||
"requirements": ["aiohttp"],
|
|
||||||
"min_bot_version": "3.5.0",
|
|
||||||
"end_user_data_statement": "This cog stores conversation history per channel in memory only."
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user