diff --git a/docs/examples/discord-py-bot/.env.example b/docs/examples/discord-py-bot/.env.example new file mode 100644 index 0000000..b4c7adf --- /dev/null +++ b/docs/examples/discord-py-bot/.env.example @@ -0,0 +1,3 @@ +.env.example +DISCORD_TOKEN="YOUR_DISCORD_BOT_TOKEN_HERE" +PERPLEXITY_API_KEY="YOUR_PPLX_API_KEY_HERE" \ No newline at end of file diff --git a/docs/examples/discord-py-bot/README.mdx b/docs/examples/discord-py-bot/README.mdx new file mode 100644 index 0000000..5aaa65b --- /dev/null +++ b/docs/examples/discord-py-bot/README.mdx @@ -0,0 +1,104 @@ +--- +title: Perplexity Discord Bot +description: A runnable discord.py bot that adds a /ask_perplexity command to your server, using the Sonar API for web-connected answers. +sidebar_position: 4 +keywords: [discord, bot, discord.py, python, chatbot, perplexity, sonar api, command, slash command] +--- + +# Perplexity Discord Bot + +A runnable `discord.py` application that adds a `/ask_perplexity` slash command to your Discord server, using Perplexity's Sonar API for real-time, web-connected answers. + +## 🌟 Features + +- **Direct Sonar API Integration**: Uses Perplexity's API for real-time, web-connected answers. +- **Slash Command Ready**: Implements a modern `/ask_perplexity` command that's easy to use. +- **Secure Configuration**: Uses environment variables (`.env`) for both Discord and Perplexity keys, keeping them safe. +- **Administrator Permissions**: Locked to server administrators by default for easy control over API usage. +- **Formatted Embeds**: Delivers answers in a clean, professional Discord embed. +- **Self-Contained Example**: Minimal, single-file code designed to be easy to run and understand. + +## 📋 Prerequisites + +- **Python 3.8+** +- **A Perplexity API Key** +- **A Discord Bot Token** + +## 🚀 Installation & Setup + +1. **Clone the Repository:** Fork and clone the `api-cookbook` repository to your local machine. + +2. **Navigate to this Example:** + ```bash + cd docs/examples/discord-py-bot/ + ``` +3. **Install Dependencies:** + ```bash + pip install -r requirements.txt + ``` +4. **Get Your Secret Keys:** + - **Perplexity API Key:** Get your key from the [Perplexity AI Account Settings](https://www.perplexity.ai/settings/api). + - **Discord Bot Token:** + 1. Go to the [Discord Developer Portal](https://discord.com/developers/applications). + 2. Click **"New Application"** and give it a name. + 3. Go to the **"Bot"** tab and click **"Reset Token"** (or "Add Bot" first if needed). + 4. Copy the token. This is your bot's password – keep it safe! + +5. **Set Up Your Environment File:** + - Rename the `.env.example` file to `.env`. + - Open the `.env` file and add your secret keys: + ``` + DISCORD_TOKEN="YOUR_DISCORD_BOT_TOKEN_HERE" + PERPLEXITY_API_KEY="YOUR_PPLX_API_KEY_HERE" + ``` + +## 🔧 Usage + +### 1. Invite Your Bot to a Server + +- In the Discord Developer Portal, go to "OAuth2" -> "URL Generator". +- Select the `bot` and `applications.commands` scopes. +- Under "Bot Permissions," select **Administrator**. +- Copy the generated URL, paste it into your browser, and invite the bot to your server. + +### 2. Run the Bot Script + +Simply execute the `bot.py` script from your terminal: +```bash +python bot.py +This will connect the bot to Discord and sync the /ask_perplexity command. +3. Use the Command in Discord +In any channel in your server, an administrator can type: +code +Code +/ask_perplexity prompt:What is the latest news in the world of generative AI? +📄 Output Example +The bot will defer the interaction and then respond with a formatted embed containing the answer: +code +Code +HatchMate [APP] +🌐 Perplexity's Response + +The latest news in generative AI includes advancements in large language models... (and so on). + +Your Prompt``` +What is the latest news in the world of generative AI? +Requested by YourUsername +code +Code +## 🛠️ Extending the Bot + +- **Role-Based Access**: Modify the permission checks to allow specific roles, not just administrators. +- **Model Selection**: Add an option to the slash command to choose between different models like `sonar-pro` or `sonar-small-online`. +- **Conversation History**: Implement a database (like SQLite or Redis) to store recent messages and send them with new prompts for conversational context. + +## ⚠️ Limitations + +- The permission system is basic (administrator-only) to keep the example simple and database-free. +- The command is single-turn and does not remember conversation history. +- API rate limits may apply based on your Perplexity account status. + +## 🙏 Acknowledgements + +- This project uses the [Perplexity AI API](https://docs.perplexity.ai/). +- Built with the [discord.py](https://discordpy.readthedocs.io/en/stable/) library. \ No newline at end of file diff --git a/docs/examples/discord-py-bot/bot.py b/docs/examples/discord-py-bot/bot.py new file mode 100644 index 0000000..6ee67be --- /dev/null +++ b/docs/examples/discord-py-bot/bot.py @@ -0,0 +1,119 @@ +# This code is a simplified example of a Discord bot that integrates with the Perplexity AI API. This is a complete, minimal bot script that someone can run directly. Notice I have simplified the permission logic to only check for administrators to remove the need for an external database, making the example much more focused on the Perplexity API. + +# bot.py +import os +import discord +from discord.ext import commands +from discord import app_commands +import openai +from dotenv import load_dotenv + +# --- Step 1: Load Environment Variables --- +# This ensures your secret keys are kept safe in a .env file. +load_dotenv() +DISCORD_TOKEN = os.getenv("DISCORD_TOKEN") +PERPLEXITY_API_KEY = os.getenv("PERPLEXITY_API_KEY") + +# --- Step 2: Bot Setup --- +# We define the bot's intents, which tell Discord what events our bot needs to receive. +intents = discord.Intents.default() +bot = commands.Bot(command_prefix="!", intents=intents) + +# --- Step 3: Create a Command Cog --- +# Cogs are how modern discord.py bots organize commands, listeners, and state. +class AIChatCog(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + + # Initialize the Perplexity AI Client using the key from our .env file. + # The `base_url` is the crucial part that directs the OpenAI library to Perplexity's API. + if PERPLEXITY_API_KEY: + self.perplexity_client = openai.OpenAI( + api_key=PERPLEXITY_API_KEY, + base_url="https://api.perplexity.ai" + ) + print("Perplexity AI Client Initialized.") + else: + self.perplexity_client = None + print("CRITICAL: PERPLEXITY_API_KEY not found in .env file.") + + # Define the slash command. + # The `has_permissions` check restricts this command to server administrators. + @app_commands.command(name="ask_perplexity", description="Ask a question to Perplexity AI (with web access).") + @app_commands.describe(prompt="The question you want to ask.") + @app_commands.checks.has_permissions(administrator=True) + async def ask_perplexity(self, interaction: discord.Interaction, prompt: str): + if not self.perplexity_client: + return await interaction.response.send_message( + "The Perplexity AI service is not configured on this bot.", + ephemeral=True + ) + + # Defer the response to give the API time to process without a timeout. + await interaction.response.defer(thinking=True) + + try: + # Create the list of messages for the API call, following the standard format. + messages = [{"role": "user", "content": prompt}] + + # Call the Perplexity API with the desired model. + response = self.perplexity_client.chat.completions.create( + model="sonar-pro", + messages=messages + ) + + answer = response.choices[0].message.content + + # Create and send a nicely formatted Discord embed for the response. + embed = discord.Embed( + title="🌐 Perplexity's Response", + description=answer, + color=discord.Color.from_rgb(0, 255, 0) # Perplexity Green + ) + embed.set_footer(text=f"Requested by {interaction.user.display_name}") + + # Truncate the original prompt if it's too long to fit in an embed field. + truncated_prompt = (prompt[:1020] + '...') if len(prompt) > 1024 else prompt + embed.add_field(name="Your Prompt", value=f"```{truncated_prompt}```", inline=False) + + await interaction.followup.send(embed=embed) + + except Exception as e: + # Inform the user if an error occurs. + error_message = f"An error occurred with the Perplexity API: {e}" + print(error_message) + await interaction.followup.send(error_message, ephemeral=True) + + # A local error handler specifically for this command's permission check. + @ask_perplexity.error + async def on_ask_perplexity_error(self, interaction: discord.Interaction, error: app_commands.AppCommandError): + if isinstance(error, app_commands.MissingPermissions): + await interaction.response.send_message("You must be an administrator to use this command.", ephemeral=True) + else: + # For other errors, print them to the console. + print(f"An unhandled error occurred: {error}") + # Potentially send a generic error message back to the user as well. + if not interaction.response.is_done(): + await interaction.response.send_message("An unexpected error occurred.", ephemeral=True) + + +# --- Step 4: Main Bot Events and Startup Logic --- +@bot.event +async def on_ready(): + print(f'Logged in as {bot.user}!') + try: + # Add the cog to the bot so its commands are registered. + await bot.add_cog(AIChatCog(bot)) + + # Sync the slash commands to Discord. This makes them appear for users. + synced = await bot.tree.sync() + print(f"Synced {len(synced)} command(s).") + except Exception as e: + print(f"Error during setup: {e}") + +# This is the entry point for running the bot. +if __name__ == "__main__": + if not DISCORD_TOKEN or not PERPLEXITY_API_KEY: + print("CRITICAL: DISCORD_TOKEN and/or PERPLEXITY_API_KEY not found in .env file. Bot cannot start.") + else: + bot.run(DISCORD_TOKEN) \ No newline at end of file diff --git a/docs/examples/discord-py-bot/requirements.txt b/docs/examples/discord-py-bot/requirements.txt new file mode 100644 index 0000000..5edec1f --- /dev/null +++ b/docs/examples/discord-py-bot/requirements.txt @@ -0,0 +1,4 @@ +# requirements.txt +discord.py +openai +python-dotenv \ No newline at end of file