diff --git a/docs/examples/discord-py-bot/.env.example b/docs/examples/discord-py-bot/.env.example
index b4c7adf..abe2f91 100644
--- a/docs/examples/discord-py-bot/.env.example
+++ b/docs/examples/discord-py-bot/.env.example
@@ -1,3 +1,5 @@
-.env.example
-DISCORD_TOKEN="YOUR_DISCORD_BOT_TOKEN_HERE"
-PERPLEXITY_API_KEY="YOUR_PPLX_API_KEY_HERE"
\ No newline at end of file
+# Discord Bot Configuration
+DISCORD_TOKEN="your_discord_bot_token_here"
+
+# Perplexity API Configuration
+PERPLEXITY_API_KEY="your_perplexity_api_key_here"
diff --git a/docs/examples/discord-py-bot/README.mdx b/docs/examples/discord-py-bot/README.mdx
index 5aaa65b..02f667f 100644
--- a/docs/examples/discord-py-bot/README.mdx
+++ b/docs/examples/discord-py-bot/README.mdx
@@ -1,104 +1,156 @@
---
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.
+description: A simple discord.py bot that integrates Perplexity's Sonar API to bring AI answers to your Discord server.
sidebar_position: 4
keywords: [discord, bot, discord.py, python, chatbot, perplexity, sonar api, command, slash command]
---
-# Perplexity Discord Bot
+A simple `discord.py` bot that integrates [Perplexity's Sonar API](https://docs.perplexity.ai/) into your Discord server. Ask questions and get AI-powered answers with web access through slash commands or by mentioning the 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
+## ✨ 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.
+- **🌐 Web-Connected AI**: Uses Perplexity's Sonar API for up-to-date information
+- **⚡ Slash Command**: Simple `/ask` command for questions
+- **💬 Mention Support**: Ask questions by mentioning the bot
+- **🔗 Source Citations**: Automatically formats and links to sources
+- **🔒 Secure Setup**: Environment-based configuration for API keys
-## 📋 Prerequisites
+## 🛠️ Prerequisites
-- **Python 3.8+**
-- **A Perplexity API Key**
-- **A Discord Bot Token**
+
+
+ **Python 3.8+** installed on your system
+
+ ```bash
+ python --version # Should be 3.8 or higher
+ ```
+
+
+
+ **Active Perplexity API Key** from [Perplexity AI Settings](https://www.perplexity.ai/settings/api)
+
+ You'll need a paid Perplexity account to access the API. See the [pricing page](https://www.perplexity.ai/pricing) for current rates.
+
+
+
+ **Discord Bot Token** from the [Discord Developer Portal](https://discord.com/developers/applications)
+
+
+
+## 🚀 Quick Start
-## 🚀 Installation & Setup
+### 1. Repository Setup
-1. **Clone the Repository:** Fork and clone the `api-cookbook` repository to your local machine.
+Clone the repository and navigate to the bot directory:
+
+```bash
+git clone https://github.com/perplexity-ai/api-cookbook.git
+cd api-cookbook/docs/examples/discord-py-bot/
+```
-2. **Navigate to this Example:**
+### 2. Install Dependencies
+
+```bash
+# Create a virtual environment (recommended)
+python -m venv venv
+source venv/bin/activate # On Windows: venv\Scripts\activate
+
+# Install required packages
+pip install -r requirements.txt
+```
+
+### 3. Configure API Keys
+
+
+
+ 1. Visit [Perplexity AI Account Settings](https://www.perplexity.ai/settings/api)
+ 2. Generate a new API key
+ 3. Copy the key to the .env file
+
+ Keep your API key secure! Never commit it to version control or share it publicly.
+
+
+
+ 1. Go to the [Discord Developer Portal](https://discord.com/developers/applications)
+ 2. Click **"New Application"** and give it a descriptive name
+ 3. Navigate to the **"Bot"** section
+ 4. Click **"Reset Token"** (or "Add Bot" if first time)
+ 5. Copy the bot token
+
+
+
+ Copy the example environment file and add your keys:
+
```bash
- cd docs/examples/discord-py-bot/
+ cp env.example .env
```
-3. **Install Dependencies:**
+
+ Edit `.env` with your credentials:
+
+ ```bash title=".env"
+ DISCORD_TOKEN="your_discord_bot_token_here"
+ PERPLEXITY_API_KEY="your_perplexity_api_key_here"
+ ```
+
+
+
+## 🎯 Usage Guide
+
+### Bot Invitation & Setup
+
+
+
+ In the Discord Developer Portal:
+ 1. Go to **OAuth2** → **URL Generator**
+ 2. Select scopes: `bot` and `applications.commands`
+ 3. Select bot permissions: `Send Messages`, `Use Slash Commands`
+ 4. Copy the generated URL
+
+
+
+ 1. Paste the URL in your browser
+ 2. Select the Discord server to add the bot to
+ 3. Confirm the permissions
+
+
+
```bash
- pip install -r requirements.txt
+ python bot.py
```
-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
+
+ You should see output confirming the bot is online and commands are synced.
+
+
+
+### How to Use
+
+**Slash Command:**
+```
+/ask [your question here]
+```
+
+
+
+**Mention the Bot:**
+```
+@YourBot [your question here]
+```
+
+
+
+## 📊 Response Format
+
+The bot provides clean, readable responses with:
+- **AI Answer**: Direct response from Perplexity's Sonar API
+- **Source Citations**: Clickable links to sources (when available)
+- **Automatic Truncation**: Responses are trimmed to fit Discord's limits
+
+## 🔧 Technical Details
+
+This bot uses:
+- **Model**: Perplexity's `sonar-pro` model
+- **Response Limit**: 2000 tokens from API, truncated to fit Discord
+- **Temperature**: 0.2 for consistent, factual responses
+- **No Permissions**: Anyone in the server can use the bot
\ No newline at end of file
diff --git a/docs/examples/discord-py-bot/bot.py b/docs/examples/discord-py-bot/bot.py
index 6ee67be..8bb5bd3 100644
--- a/docs/examples/discord-py-bot/bot.py
+++ b/docs/examples/discord-py-bot/bot.py
@@ -1,119 +1,181 @@
-# 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
+import logging
+import re
+
+# Basic logging
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
-# --- Step 1: Load Environment Variables ---
-# This ensures your secret keys are kept safe in a .env file.
+# Load environment variables
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.
+# Bot setup
intents = discord.Intents.default()
+intents.message_content = True
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
+# Perplexity client
+perplexity_client = openai.OpenAI(
+ api_key=PERPLEXITY_API_KEY,
+ base_url="https://api.perplexity.ai"
+) if PERPLEXITY_API_KEY else None
- # 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.")
+@bot.event
+async def on_ready():
+ """Bot startup"""
+ logger.info(f"Bot {bot.user} is ready!")
+ await bot.tree.sync()
+ logger.info("Commands synced")
- # 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
- )
+@bot.tree.command(name="ask", description="Ask Perplexity AI a question")
+@app_commands.describe(question="Your question")
+async def ask(interaction: discord.Interaction, question: str):
+ """Ask Perplexity AI a question"""
+ if not perplexity_client:
+ await interaction.response.send_message("❌ Perplexity AI not configured", ephemeral=True)
+ return
- # Defer the response to give the API time to process without a timeout.
- await interaction.response.defer(thinking=True)
+ await interaction.response.defer()
+
+ try:
+ response = perplexity_client.chat.completions.create(
+ model="sonar-pro",
+ messages=[
+ {
+ "role": "system",
+ "content": "You are a helpful AI assistant. Provide clear, accurate answers with citations."
+ },
+ {"role": "user", "content": question}
+ ],
+ max_tokens=2000,
+ temperature=0.2
+ )
- 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
+ answer = response.choices[0].message.content
+ formatted_answer = format_citations(answer, response)
+
+ # Truncate if too long
+ if len(formatted_answer) > 2000:
+ formatted_answer = formatted_answer[:1997] + "..."
+
+ await interaction.followup.send(formatted_answer)
+
+ except Exception as e:
+ logger.error(f"Error: {e}")
+ await interaction.followup.send("❌ Sorry, an error occurred. Please try again.", ephemeral=True)
+
+@bot.event
+async def on_message(message):
+ """Handle mentions"""
+ if message.author == bot.user or message.author.bot:
+ return
+
+ # Check if bot is mentioned
+ if bot.user in message.mentions and perplexity_client:
+ # Remove mention from content
+ content = message.content.replace(f'<@{bot.user.id}>', '').replace(f'<@!{bot.user.id}>', '').strip()
+
+ if not content:
+ await message.reply("Hello! Ask me any question.")
+ return
+
+ async with message.channel.typing():
+ try:
+ response = perplexity_client.chat.completions.create(
+ model="sonar-pro",
+ messages=[
+ {
+ "role": "system",
+ "content": "You are a helpful AI assistant. Provide clear, accurate answers with citations."
+ },
+ {"role": "user", "content": content}
+ ],
+ max_tokens=2000,
+ temperature=0.2
+ )
+
+ answer = response.choices[0].message.content
+ formatted_answer = format_citations(answer, response)
+
+ # Truncate if too long
+ if len(formatted_answer) > 2000:
+ formatted_answer = formatted_answer[:1997] + "..."
+
+ await message.reply(formatted_answer)
+
+ except Exception as e:
+ logger.error(f"Error: {e}")
+ await message.reply("❌ Sorry, an error occurred. Please try again.")
+
+ await bot.process_commands(message)
- # 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}")
+def format_citations(text: str, response_obj) -> str:
+ """Simple citation formatting that actually works"""
+ # Get search results from response
+ search_results = []
+
+ if hasattr(response_obj, 'search_results') and response_obj.search_results:
+ search_results = response_obj.search_results
+ elif hasattr(response_obj, 'model_dump'):
+ dumped = response_obj.model_dump()
+ search_results = dumped.get('search_results', [])
+
+ if not search_results:
+ return text
+
+ # Find existing citations like [1], [2], etc.
+ citation_pattern = r'\[(\d+)\]'
+ citations = re.findall(citation_pattern, text)
+
+ if citations:
+ # Replace existing citations with clickable links
+ def replace_citation(match):
+ num = int(match.group(1))
+ idx = num - 1
- # 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)
+ if 0 <= idx < len(search_results):
+ result = search_results[idx]
+
+ # Extract URL from search result
+ url = ""
+ if isinstance(result, dict):
+ url = result.get('url', '')
+ elif hasattr(result, 'url'):
+ url = result.url
+
+ if url:
+ return f"[[{num}]](<{url}>)"
- await interaction.followup.send(embed=embed)
+ return f"[{num}]"
+
+ text = re.sub(citation_pattern, replace_citation, text)
+ else:
+ # No citations in text, add them at the end
+ citations_list = []
+ for i, result in enumerate(search_results[:5]): # Limit to 5
+ url = ""
+ if isinstance(result, dict):
+ url = result.get('url', '')
+ elif hasattr(result, 'url'):
+ url = result.url
- 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))
+ if url:
+ citations_list.append(f"[[{i+1}]](<{url}>)")
- # 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}")
+ if citations_list:
+ text += "\n\n**Sources:** " + " ".join(citations_list)
+
+ return text
-# 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.")
+ print("❌ Missing DISCORD_TOKEN or PERPLEXITY_API_KEY in .env file")
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
index 5edec1f..18e3a13 100644
--- a/docs/examples/discord-py-bot/requirements.txt
+++ b/docs/examples/discord-py-bot/requirements.txt
@@ -1,4 +1,3 @@
-# requirements.txt
-discord.py
-openai
-python-dotenv
\ No newline at end of file
+discord.py>=2.3.0
+openai>=1.0.0
+python-dotenv>=1.0.0
diff --git a/static/img/discord-py-bot-demo.png b/static/img/discord-py-bot-demo.png
new file mode 100644
index 0000000..3f65c57
Binary files /dev/null and b/static/img/discord-py-bot-demo.png differ
diff --git a/static/img/discord-py-bot-mention-command.png b/static/img/discord-py-bot-mention-command.png
new file mode 100644
index 0000000..243a7ee
Binary files /dev/null and b/static/img/discord-py-bot-mention-command.png differ
diff --git a/static/img/discord-py-bot-slash-command.png b/static/img/discord-py-bot-slash-command.png
new file mode 100644
index 0000000..b92e977
Binary files /dev/null and b/static/img/discord-py-bot-slash-command.png differ