-
-
Notifications
You must be signed in to change notification settings - Fork 26
How to Write a Custom Plugin
This is a step-by-step guide to demonstrate how to write a custom LetMeDoItAI plugin.
You may refer to our original post at https://github.com/eliranwong/letmedoit/issues/31
In this demonstration, I am going to develop a LetMeDoIt AI plugin to check the latest news about something.
To research about how to perform the task for searching the latest news, I used LetMeDoIt AI to ask Codey to provide me with related information.
In LetMeDoIt prompt, I entered:
Ask Codey how to check the latest news in my area, for example, London, UK, with python?
I got the following response:
import feedparser
# Get the latest news from a specific RSS feed
feed_url = "https://news.google.com/rss/search?q=London+UK&hl=en-US&gl=US&ceid=US:en"
feed = feedparser.parse(feed_url)
# Print the title and link of each news item
for entry in feed.entries:
print(entry.title)
print(entry.link)
I need to develop a function method that accepts keywords as argument for searching the latest news.
Based on the research in Step 1 above, the url for searching the news is:
"https://news.google.com/rss/search?q=London+UK&hl=en-US&gl=US&ceid=US:en"
I observed two things:
- Two keywords "London" and "UK" placed between "q=" and "&"
- The keywords are connected with a "+" sign
Therefore, I modified the code and developed a simple function method below that can accept a list for keywords for searching the latest news:
import feedparser
# Get the latest news from a specific RSS feed
def search_latest_news(keywords: str) -> None:
feed_url = f"https://news.google.com/rss/search?q={keywords}&hl=en-US&gl=US&ceid=US:en"
feed = feedparser.parse(feed_url)
# Print the title and link of each news item
for entry in feed.entries:
print(entry.title)
print(entry.link)
As I want LetMeDoIt AI to extract the keywords from user input, which is natural language, I need to develop a function signature to work with ChatGPT model that supports function calling.
I decide that I need only one variable in the signature, i.e. keyword
Below is the signature that I prepared for the plugin:
functionSignature = {
"name": "search_latest_news",
"description": "Search the latest news with given keywords",
"parameters": {
"type": "object",
"properties": {
"keywords": {
"type": "string",
"description": "The keywords for searching the latest news, delimited by plus sign '+'. For example, return 'London+UK' if keywords are 'London' and 'UK'.",
},
},
"required": ["keywords"],
},
}
Add the following lines to the plugin. You may read the self-explanatory comments in this snippet.
# Add the following line to tell LetMeDoIt AI that this plugin work with function calling feature.
config.pluginsWithFunctionCall.append("search_latest_news")
# The following line adds the function signature, that we prepared in STEP 3, to the full list of all function signatures that work with LetMeDoIt AI.
config.chatGPTApiFunctionSignatures.append(functionSignature)
# The following line tells LetMeDoIt AI to call the method "search_latest_news" that we added in this plugin when the function signature "search_latest_news" is loaded.
config.chatGPTApiAvailableFunctions["search_latest_news"] = search_latest_news
# The following line is optional. It adds an input suggestion to LetMeDoIt AI user input prompt
config.inputSuggestions.append("Give me the latest news about ")
In this step, we modified the task execution method we developed in STEP 2.
As LetMeDoIt AI passes all arguments to the called function as a dictionary, we made the following changes:
- change the argument type to dictionary and name the argument as "function_args".
- add a line, the first line, in the method to get the string "keywords" from the dictionary "function_args".
- Return an empty string to tell LetMeDoIt AI not to generate a follow-up response after the method is executed.
import feedparser
# Get the latest news from a specific RSS feed
def search_latest_news(function_args: dict) -> str:
keywords = function_args.get("keywords")
feed_url = f"https://news.google.com/rss/search?q={keywords}&hl=en-US&gl=US&ceid=US:en"
feed = feedparser.parse(feed_url)
# Print the title and link of each news item
for entry in feed.entries:
print(entry.title)
print(entry.link)
return ""
In this example, we make it simple to print all the information when the function method "search_latest_news" is called and return an empty string.
Depending on what you want, you can finish the function method differently. For example, if you want to pass the retrieved information to ChatGPT to generate a response based on the retrieved information, instead of printing all information directly, you can modify the method like this one below:
import feedparser, json
# Get the latest news from a specific RSS feed
def search_latest_news(function_args: dict) -> str:
keywords = function_args.get("keywords")
feed_url = f"https://news.google.com/rss/search?q={keywords}&hl=en-US&gl=US&ceid=US:en"
feed = feedparser.parse(feed_url)
# Pass the retrieved information to ChatGPT to generate a further response
info = {}
for index, entry in enumerate(feed.entries):
info[f"news {index}"] = {
"title": entry.title,
"link": entry.link,
}
return json.dumps(info)
This step is optional. I modified the function method further to display the information with print methods shared in object "config". In object "config", method "print" supports word wrap feature, and method "print2" print all content in color. In this modified method, each entry is divided by "config.divider". "config.stopSpinning" is added to stop spinning before displaying retrieved information. In addition, I limit the results up to 10 entries.
from letmedoit import config
import feedparser
# Get the latest news from a specific RSS feed
def search_latest_news(function_args: dict) -> str:
keywords = function_args.get("keywords")
feed_url = f"https://news.google.com/rss/search?q={keywords}&hl=en-US&gl=US&ceid=US:en"
feed = feedparser.parse(feed_url)
# Print the title and link of each news item
config.stopSpinning()
config.print2(config.divider)
for index, entry in enumerate(feed.entries):
if index < 10:
if not index == 0:
config.print2(config.divider)
config.print(entry.title)
print(entry.link)
config.print2(config.divider)
return ""
- Open a text editor
- Save the following content with a filename "search latest news.py" in "~/letmedoit/plugins"
Remarks:
- "~/letmedoit/plugins" is the default storage directory for custom plugins
- You may change the storage directory via LetMeDoIt action menu
from letmedoit import config
import feedparser
# Function method to get the latest news from a specific RSS feed
def search_latest_news(function_args: dict) -> str:
keywords = function_args.get("keywords")
feed_url = f"https://news.google.com/rss/search?q={keywords}&hl=en-US&gl=US&ceid=US:en"
feed = feedparser.parse(feed_url)
# Print the title and link of each news item
config.stopSpinning()
config.print2(config.divider)
for index, entry in enumerate(feed.entries):
if index < 10:
if not index == 0:
config.print2(config.divider)
config.print(entry.title)
print(entry.link)
config.print2(config.divider)
return ""
# Function signature to work with ChatGPT function calling
functionSignature = {
"name": "search_latest_news",
"description": "Search the latest news with given keywords",
"parameters": {
"type": "object",
"properties": {
"keywords": {
"type": "string",
"description": "The keywords for searching the latest news, delimited by plus sign '+'. For example, return 'London+UK' if keywords are 'London' and 'UK'.",
},
},
"required": ["keywords"],
},
}
# Add the following line to tell LetMeDoIt AI that this plugin work with function calling feature.
config.pluginsWithFunctionCall.append("search_latest_news")
# The following line adds the function signature, that we prepared in STEP 3, to the full list of all function signatures that work with LetMeDoIt AI.
config.chatGPTApiFunctionSignatures.append(functionSignature)
# The following line tells LetMeDoIt AI to call the method "search_latest_news" that we added in this plugin when the function signature "search_latest_news" is loaded.
config.chatGPTApiAvailableFunctions["search_latest_news"] = search_latest_news
# The following line is optional. It adds an input suggestion to LetMeDoIt AI user input prompt
config.inputSuggestions.append("Give me the latest news about ")
Check if your plugin's dependencies are installed with LetMeDoIt AI package by default at https://github.com/eliranwong/letmedoit/blob/main/package/letmedoit/requirements.txt
If not, activate your LetMeDoIt AI environment and install dependencies.
In this case, we install package "feedparser", run in terminal:
cd ~/apps/letmedoit/bin/activate
pip install feedparser
Remarks: "~/apps/letmedoit" is where we set up an environment for installing LetMeDoIt AI on our tested device.
I launched LetMeDoIt AI and entered the following prompt:
Give me the latest news about ChatGPT
Below is the screenshot of the result.
To share your plugin with other users, submit a pull request to our repository at:
Installation
Installation on Android
Install a Supported Python Version
Install ffmpeg
Android Support
Install LetMeDoIt AI on Android Termux App
Automatic Upgrade Option
Quick Guide
Action Menu
ChatGPT API Key
Use GPT4 Models
Google API Setup
ElevenLabs API Setup
OpenWeatherMap API Setup
Run Local LLM Offline
Token Management
Command Line Interface Options
Command Execution
Chat-only Features
Developer Mode
Save Chart Content Locally
Work with Text Selection
Work with File Selection
System Tray
Custom Key Bindings
Examples
Features
Change Assistant Name
Setup Multiple LetMeDoIt Assistants
Memory Capabilities
Data Visualization
Analyze Files
Analyze Images
Analyze Audio
Google and Outlook Calendars
Python Code Auto‐heal Feature
Integration with AutoGen
Integration with Google AI Tools
Integration with Open Interpreter
Speak to LetMeDoIt AI
LetMeDoIt Speaks
Speak multi‐dialects
Create a map anytime
Modify your images with simple words
Work with Database Files
Create a Team of AI Assistants
Search and Load Chat Records
Search Weather Information
Search Financial Data
Social Media
Plugins ‐ Overview
Plugins - How to Write a Custom Plugin
Plugins ‐ Add Aliases
Plugins ‐ Input Suggestions
Plugins ‐ Install Additional Packages
Plugins ‐ Predefined Contexts
Plugins ‐ Transform Text Output
Plugins ‐ Work with LetMeDoIt AI Configurations
Plugins ‐ Function Calling
Plugins ‐ Run Codes with Specific Packages
Plugins ‐ Work with Non‐conversational Model
Plugins ‐ Integrate Text‐to‐speech Feature
Plugins ‐ Integrate Other Shared Utilities