A modern WhatsApp bot library with OpenAI GPT integration on Python
Project description
WhatsApp GPT Bot Library for Python
A modern, state-based WhatsApp bot library with OpenAI GPT integration, built on top of whatsapp-chatbot-python and GREEN-API.
Features
- OpenAI GPT model integration for intelligent responses
- Support for multiple GPT models (GPT-3.5, GPT-4, GPT-4o, o1)
- Multimodal capabilities with image processing support
- Voice message transcription using Whisper API
- Comprehensive message handling for various WhatsApp media types
- Middleware architecture for customizing message and response processing
- Built-in conversation history management
- State-based conversation flow inherited from base library
- Python type hints and comprehensive docstrings
Installation
pip install whatsapp-chatgpt-python
The dependencies (openai, whatsapp-chatbot-python, and requests) will be installed automatically.
Prerequisites
Before using the bot, you'll need:
- A registered account with GREEN-API
- An instance ID and API token from your GREEN-API account
- An OpenAI API key for GPT access
Quick Start
from whatsapp_chatgpt_python import WhatsappGptBot
# Initialize the bot
bot = WhatsappGptBot(
id_instance="your-instance-id",
api_token_instance="your-api-token",
openai_api_key="your-openai-api-key",
model="gpt-4o",
system_message="You are a helpful assistant."
)
# Start the bot
bot.run_forever()
Core Components
Bot Configuration
The bot inherits all configuration options from the base GreenAPIBot including the ability to customize GREEN-API
instance settings.
Complete configuration options for the WhatsappGptBot:
bot = WhatsappGptBot(
# Required parameters
id_instance="your-instance-id",
api_token_instance="your-api-token",
openai_api_key="your-openai-api-key",
# Optional GPT-specific parameters
model="gpt-4o", # Default model
max_history_length=10, # Maximum messages in conversation history
system_message="You are a helpful assistant.", # System message to set behavior
temperature=0.5, # Temperature for response generation
error_message="Sorry, I couldn't process your request. Please try again.",
session_timeout=1800, # Session timeout in seconds (30 minutes)
# Optional parameters from base bot
bot_debug_mode=False, # Enable debug logs
debug_mode=False, # Enable API debug mode
raise_errors=True, # Whether to raise API errors
settings={ # GREEN-API instance settings
"webhookUrl": "", # Custom webhook URL
"webhookUrlToken": "", # Webhook security token
"delaySendMessagesMilliseconds": 500, # Delay between messages
"markIncomingMessagesReaded": "yes", # Mark messages as read
"incomingWebhook": "yes", # Enable incoming webhooks
"keepOnlineStatus": "yes", # Keep WhatsApp online status
"pollMessageWebhook": "yes", # Enable poll message webhooks
}
)
WhatsappGptBot
Main class for creating and managing your OpenAI-powered WhatsApp bot:
from whatsapp_chatgpt_python import WhatsappGptBot
bot = WhatsappGptBot(
id_instance="your-instance-id",
api_token_instance="your-api-token",
openai_api_key="your-openai-api-key",
model="gpt-4o",
system_message="You are a helpful assistant specializing in customer support.",
max_history_length=15,
temperature=0.7,
settings={
"webhookUrl": "",
"markIncomingMessagesReaded": "yes",
"keepOnlineStatus": "yes",
"delaySendMessagesMilliseconds": 500,
}
)
# Start the bot
bot.run_forever()
Message Handling
The bot automatically handles different types of WhatsApp messages and converts them into a format understood by OpenAI's models.
Supported Message Types
- Text: Regular text messages
- Image: Photos with optional captions (supported in vision-capable models)
- Audio: Voice messages with automatic transcription
- Video: Video messages with captions
- Document: File attachments
- Poll: Poll messages and poll updates
- Location: Location sharing
- Contact: Contact sharing
Message Handler Registry
The bot uses a registry of message handlers to process different message types:
# Access the registry
registry = bot.message_handlers
# Create a custom message handler
class CustomMessageHandler(MessageHandler):
def can_handle(self, notification):
return notification.get_message_type() == "custom-type"
async def process_message(self, notification, openai_client=None, model=None):
# Process the message
return "Processed content"
# Register the custom handler
bot.register_message_handler(CustomMessageHandler())
# Replace an existing handler
bot.replace_handler(TextMessageHandler, CustomTextHandler())
Middleware System
The middleware system allows for customizing message processing before sending to GPT and response processing before sending back to the user.
Adding Message Middleware
# Process messages before sending to GPT
def custom_message_middleware(notification, message_content, messages, session_data):
# Add custom context to the conversation
if notification.get_message_type() == "textMessage" and notification.chat.endswith("@c.us"):
# Add context to the message
enhanced_content = f"[User message] {message_content}"
return {
"message_content": enhanced_content,
"messages": messages
}
return {
"message_content": message_content,
"messages": messages
}
# Add the middleware
bot.add_message_middleware(custom_message_middleware)
Adding Response Middleware
# Process GPT responses before sending to user
def custom_response_middleware(response, messages, session_data):
# Format or modify the response
formatted_response = response.replace("GPT", "Assistant").strip()
# You can also modify the messages that will be saved in history
return {
"response": formatted_response,
"messages": messages
}
# Add the middleware
bot.add_response_middleware(custom_response_middleware)
Session Data
The GPT bot extends the base session data with conversation-specific information:
@dataclass
class GPTSessionData:
"""Session data for GPT conversations"""
messages: List[Dict[str, Any]] = field(default_factory=list)
last_activity: int = field(default_factory=lambda: int(time.time()))
user_data: Dict[str, Any] = field(default_factory=dict)
context: Dict[str, Any] = field(default_factory=dict)
You can access and modify this data in your middleware:
def message_middleware(notification, content, messages, session_data):
# Set context variables
if "variables" not in session_data.context:
session_data.context["variables"] = {}
session_data.context["variables"]["last_interaction"] = int(time.time())
return {"message_content": content, "messages": messages}
Utilities
The library provides several utility functions for common tasks:
Media Handling
from whatsapp_chatgpt_python import Utils
# Download media from a URL
temp_file = await Utils.download_media("https://example.com/image.jpg")
# Transcribe audio
from openai import OpenAI
openai_client = OpenAI(api_key="your-openai-api-key")
transcript = await Utils.transcribe_audio("/path/to/audio.ogg", openai_client)
# Clean up after processing
import os
os.unlink(temp_file)
Conversation Management
from whatsapp_chatgpt_python import Utils
# Trim conversation history
trimmed_messages = Utils.trim_conversation_history(
messages,
10, # max messages
True # preserve system message
)
# Estimate token usage
estimated_tokens = Utils.estimate_tokens(messages)
Supported OpenAI Models
The library supports a variety of OpenAI models:
GPT-4 Models
- gpt-4
- gpt-4-turbo
- gpt-4-turbo-preview
- gpt-4-1106-preview
- gpt-4-0125-preview
- gpt-4-32k
GPT-4o Models
- gpt-4o (default)
- gpt-4o-mini
- gpt-4o-2024-05-13
GPT-3.5 Models
- gpt-3.5-turbo
- gpt-3.5-turbo-16k
- gpt-3.5-turbo-1106
- gpt-3.5-turbo-0125
o1 Models
- o1
- o1-mini
- o1-preview
Image-Capable Models
The following models can process images:
- gpt-4o
- gpt-4o-mini
- gpt-4-vision-preview
- gpt-4-turbo
- gpt-4-turbo-preview
Advanced Configuration
Custom Command Handling
Since the library is built on whatsapp-chatbot-python, you can use all the command/filter features of the base library:
@bot.router.message(command="help")
def help_handler(notification):
help_text = (
"🤖 *WhatsApp GPT Bot* 🤖\n\n"
"Available commands:\n"
"• */help* - Show this help message\n"
"• */clear* - Clear conversation history\n"
"• */info* - Show bot information"
)
notification.answer(help_text)
# Clear conversation history command
@bot.router.message(command="clear")
def clear_history_handler(notification):
chat_id = notification.chat
# Get session data
session_data = bot.get_session_data(chat_id)
# Find system message if it exists
system_message = None
for msg in session_data.messages:
if msg.get("role") == "system":
system_message = msg
break
# Reset messages but keep system message
if system_message:
session_data.messages = [system_message]
else:
session_data.messages = []
# Update session
bot.update_session_data(chat_id, session_data)
notification.answer("🗑️ Conversation history cleared! Let's start fresh.")
Bypassing GPT for Certain Commands
You can create handlers that don't process with GPT:
@bot.router.message(command="weather")
def weather_handler(notification):
notification.answer(
"🌤️ This is a placeholder weather response from a custom handler.\n\n"
"In a real bot, this would fetch actual weather data from an API.\n\n"
"This handler demonstrates skipping GPT processing."
)
Explicit GPT Processing
You can explicitly request GPT processing after handling a message:
@bot.router.message(text_message="recommend")
def recommend_handler(notification):
# Add a prefix message
notification.answer("I'll give you a recommendation. Let me think...")
# Request GPT processing as well
notification.process_with_gpt()
You can also modify the message before sending it to GPT using the custom_message parameter:
# Echo handler that forwards a modified message to GPT
@bot.router.message(command="echo")
def echo_handler(notification):
# Get the rest of the message after the command
message_text = notification.message_text
command_parts = message_text.split(maxsplit=1)
if len(command_parts) > 1:
echo_text = command_parts[1]
notification.answer(f"You said: {echo_text}\n\nI'll ask GPT for more insights...")
# Process with GPT, but pass only the actual message (without the command)
notification.process_with_gpt(custom_message=echo_text)
else:
notification.answer("Please provide text after the /echo command.")
This is useful when you want to preprocess the message before it's sent to GPT, such as removing command prefixes, formatting the input, or adding context.
Advanced Message Processing
# Check if current model supports images
if bot.supports_images():
# Handle image-based workflow
pass
Complete Example Bot
Here's a complete example of a WhatsApp GPT bot with custom handlers and middleware:
import os
import time
import logging
from whatsapp_chatgpt_python import (
WhatsappGptBot,
ImageMessageHandler,
TextMessageHandler
)
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('whatsapp_chatgpt_python')
# Get environment variables
ID_INSTANCE = os.environ.get("INSTANCE_ID")
API_TOKEN = os.environ.get("INSTANCE_TOKEN")
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
# Initialize the bot
bot = WhatsappGptBot(
id_instance=ID_INSTANCE,
api_token_instance=API_TOKEN,
openai_api_key=OPENAI_API_KEY,
model="gpt-4o", # Uses the GPT-4o model (which supports images)
system_message="You are a helpful assistant. Be concise and friendly in your replies.",
max_history_length=15, # Keep last 15 messages in conversation history
temperature=0.7, # Slightly more creative responses
session_timeout=1800, # Sessions expire after 30 minutes of inactivity
error_message="Sorry, your message could not be processed.", # Custom error message
)
# Custom image handler that provides enhanced instructions for images
class EnhancedImageHandler(ImageMessageHandler):
async def process_message(self, notification, openai_client=None, model=None):
# Call the parent class method to get the base result
result = await super().process_message(notification, openai_client, model)
# For text-only responses (non-vision models)
if isinstance(result, str):
return result.replace(
"[The user sent an image",
"[The user sent an image. Analyze what might be in it based on any caption"
)
# For vision-capable models, enhance the text instruction
if isinstance(result, list) and len(result) > 0 and isinstance(result[0], dict):
if result[0].get('type') == 'text':
text = result[0].get('text', '')
if text == "Analyzing this image":
result[0]['text'] = "Describe this image in detail and what you see in it."
return result
# Example of a custom text handler
class EnhancedTextHandler(TextMessageHandler):
async def process_message(self, notification, *args, **kwargs):
# Get the text message using the parent method
text = await super().process_message(notification, *args, **kwargs)
if not text:
return text
lower_text = text.lower()
if any(term in lower_text for term in ['code', 'function', 'script', 'program']):
return f"🧑💻 CODE REQUEST: {text}\n\n[I'll format my code response with proper syntax highlighting]"
elif text.endswith('?') or text.lower().startswith(
('what', 'why', 'how', 'when', 'where', 'who', 'can', 'could')):
return f"❓ QUESTION: {text}\n\n[I'll provide a clear and comprehensive answer]"
return text
# Replace the default handlers with our enhanced versions
bot.replace_handler(ImageMessageHandler, EnhancedImageHandler())
bot.replace_handler(TextMessageHandler, EnhancedTextHandler())
# Middleware to log all messages and add tracking information
def logging_middleware(notification, message_content, messages, session_data):
user_id = notification.sender
if isinstance(message_content, str):
content_display = message_content[:100] + "..." if len(message_content) > 100 else message_content
else:
content_display = "complex content (likely contains media)"
logger.info(f"Message from {user_id}: {content_display}")
# Add tracking information to session context
if not session_data.context.get("variables"):
session_data.context["variables"] = {}
session_data.context["variables"].update({
"last_interaction": int(time.time()),
"message_count": session_data.context.get("variables", {}).get("message_count", 0) + 1
})
# Return unchanged content and messages
return {"message_content": message_content, "messages": messages}
# Middleware to format responses before sending to user
def formatting_middleware(response, messages, session_data):
# Format response by adding a signature at the end of longer messages
formatted_response = response.strip()
# Don't add signature to short responses
if len(formatted_response) > 100 and not formatted_response.endswith("_"):
message_count = session_data.context.get("variables", {}).get("message_count", 0)
formatted_response += f"\n\n_Message #{message_count} • Powered by GPT_"
return {"response": formatted_response, "messages": messages}
# Add the middleware
bot.add_message_middleware(logging_middleware)
bot.add_response_middleware(formatting_middleware)
# Command handler for /clear to reset conversation history
@bot.router.message(command="clear")
def clear_history_handler(notification):
chat_id = notification.chat
# Get session data
session_data = bot.get_session_data(chat_id)
# Find system message if it exists
system_message = None
for msg in session_data.messages:
if msg.get("role") == "system":
system_message = msg
break
# Reset messages but keep system message
if system_message:
session_data.messages = [system_message]
else:
session_data.messages = []
# Update session
bot.update_session_data(chat_id, session_data)
notification.answer("🗑️ Conversation history cleared! Let's start fresh.")
# Command handler for /help to show available commands
@bot.router.message(command="help")
def help_handler(notification):
help_text = (
"🤖 *WhatsApp GPT Bot* 🤖\n\n"
"Available commands:\n"
"• */help* - Show this help message\n"
"• */clear* - Clear conversation history\n"
"• */info* - Show bot information\n"
"• */weather* - Example of a handler that skips GPT\n\n"
"You can send text, images, audio, and more. I'll respond intelligently to your messages."
)
notification.answer(help_text)
# Add an info command
@bot.router.message(command="info")
def info_handler(notification):
chat_id = notification.chat
session_data = bot.get_session_data(chat_id)
# Get session statistics
message_count = len(session_data.messages) - 1 # Subtract system message
if message_count < 0:
message_count = 0
vision_capable = "Yes" if bot.supports_images() else "No"
info_text = (
"📊 *Bot Information* 📊\n\n"
f"Model: {bot.get_model()}\n"
f"Vision capable: {vision_capable}\n"
f"Messages in current session: {message_count}\n"
f"Max history length: {bot.max_history_length}\n"
f"Session timeout: {bot.session_timeout} seconds\n\n"
"To clear the current conversation, use */clear*"
)
notification.answer(info_text)
# Example weather handler that skips GPT processing
@bot.router.message(command="weather")
def weather_handler(notification):
notification.answer(
"🌤️ This is a placeholder weather response from a custom handler.\n\n"
"In a real bot, this would fetch actual weather data from an API.\n\n"
"This handler demonstrates skipping GPT processing."
)
# Start the bot
if __name__ == "__main__":
logger.info("Starting WhatsApp GPT Bot...")
logger.info(f"Using model: {bot.get_model()}")
bot.run_forever()
License
MIT
Technologies Used
This library is built on top of:
- whatsapp-chatbot-python - The base WhatsApp bot library
- GREEN-API - WhatsApp API service for bot integration
- OpenAI API - For GPT model integration
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file whatsapp_chatgpt_python-1.0.0.tar.gz.
File metadata
- Download URL: whatsapp_chatgpt_python-1.0.0.tar.gz
- Upload date:
- Size: 25.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94640b96932bd135f6c58da8e1cd0d20a1c3dd200d8c96fb54100fff655ada66
|
|
| MD5 |
c752056d44b17b11b7de44e0fa08b48b
|
|
| BLAKE2b-256 |
6c7e7d4b2371201878de5ffe4fc76e7e4ef840e5a13235c6d4b710cc3f28a82a
|
File details
Details for the file whatsapp_chatgpt_python-1.0.0-py3-none-any.whl.
File metadata
- Download URL: whatsapp_chatgpt_python-1.0.0-py3-none-any.whl
- Upload date:
- Size: 29.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb4632f710f185e350c509ace4394241fb72dcce3c6faea0c65b9f00083d19e8
|
|
| MD5 |
e96ff8c6cf717ee7021f5cea7ec465b3
|
|
| BLAKE2b-256 |
f70647e2033514b0730fa5b6c1a905b92f893335cf308e73811dc1e788723641
|