This repository has been archived by the owner on Mar 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 732
Adding ChatGPT plugin tool #405
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# ChatGPT Plugin Tool | ||
|
||
This tool allows Agents to load a plugin using a ChatGPT manifest file, and have the Agent interact with it. | ||
|
||
## Usage | ||
|
||
This tool has more extensive example usage documented in a Jupyter notebook [here](https://github.com/emptycrown/llama-hub/tree/main/llama_hub/tools/notebooks/chatgpt_plugin.ipynb) | ||
|
||
```python | ||
# Load the manifest | ||
import requests | ||
import yaml | ||
f = requests.get('https://raw.githubusercontent.com/sisbell/chatgpt-plugin-store/main/manifests/today-currency-converter.oiconma.repl.co.json').text | ||
manifest = yaml.load(f, Loader=yaml.Loader) | ||
|
||
from llama_hub.tools.chatgpt_plugin.base import ChatGPTPluginToolSpec | ||
from llama_index.agent import OpenAIAgent | ||
from llama_hub.tools.requests.base import RequestsToolSpec | ||
|
||
requests_spec = RequestsToolSpec() | ||
plugin_spec = ChatGPTPluginToolSpec(manifest) | ||
# OR | ||
plugin_spec = ChatGPTPluginToolSpec(manifest_url='https://raw.githubusercontent.com/sisbell/chatgpt-plugin-store/main/manifests/today-currency-converter.oiconma.repl.co.json') | ||
|
||
agent = OpenAIAgent.from_tools([*plugin_spec.to_tool_list(), *requests_spec.to_tool_list()], verbose=True) | ||
print(agent.chat("Convert 100 euros to CAD")) | ||
``` | ||
|
||
`describe_plugin`: Describe the plugin that has been loaded. | ||
`load_openapi_spec`: Returns the parsed OpenAPI spec that the class was initialized with | ||
|
||
In addition to the above method, this tool makes all of the tools available from the OpenAPI Tool Spec and Requests Tool Spec available to the agent. The plugin OpenAPI defintion is loaded into the OpenAPI tool spec, and authentication headers are passed in to the Requests tool spec | ||
|
||
|
||
This loader is designed to be used as a way to load data as a Tool in a Agent. See [here](https://github.com/emptycrown/llama-hub/tree/main) for examples. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""init.py""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
"""ChatGPT Plugiun Tool.""" | ||
|
||
from typing import List, Optional | ||
|
||
from llama_index.readers.schema.base import Document | ||
from llama_index.tools.tool_spec.base import BaseToolSpec | ||
from llama_hub.tools.openapi.base import OpenAPIToolSpec | ||
import requests | ||
import yaml | ||
|
||
class ChatGPTPluginToolSpec(BaseToolSpec): | ||
"""ChatGPT Plugin Tool | ||
|
||
This tool leverages the OpenAPI tool spec to automatically load ChatGPT | ||
plugins from a manifest file. | ||
You should also provide the Requests tool spec to allow the Agent to make calls to the OpenAPI endpoints | ||
To use endpoints with authorization, use the Requests tool spec with the authorization headers | ||
""" | ||
|
||
spec_functions = ['load_openapi_spec', 'describe_plugin'] | ||
|
||
def __init__(self, manifest: Optional[dict] = None, manifest_url: Optional[str] = None): | ||
if manifest and manifest_url: | ||
raise ValueError('You cannot provide both a manifest and a manifest_url') | ||
elif manifest: | ||
pass | ||
elif manifest_url: | ||
response = requests.get(manifest_url).text | ||
manifest = yaml.load(response, Loader=yaml.Loader) | ||
else: | ||
raise ValueError('You must provide either a manifest or a manifest_url') | ||
|
||
if manifest['api']['type'] != 'openapi': | ||
raise ValueError(f'API type must be "openapi", not "{manifest["api"]["type"]}"') | ||
|
||
if manifest['auth']['type'] != 'none': | ||
raise ValueError(f'Authentication cannot be supported for ChatGPT plugins') | ||
|
||
self.openapi = OpenAPIToolSpec(url=manifest['api']['url']) | ||
|
||
self.plugin_description = f""" | ||
'human_description': {manifest['description_for_human']} | ||
'model_description': {manifest['description_for_model']} | ||
""" | ||
|
||
def load_openapi_spec(self) -> List[Document]: | ||
""" | ||
You are an AI agent specifically designed to retrieve information by making web requests to an API based on an OpenAPI specification. | ||
|
||
Here's a step-by-step guide to assist you in answering questions: | ||
|
||
1. Determine the base URL required for making the request | ||
|
||
2. Identify the relevant paths necessary to address the question | ||
|
||
3. Find the required parameters for making the request | ||
|
||
4. Perform the necessary requests to obtain the answer | ||
|
||
Returns: | ||
Document: A List of Document objects describing the OpenAPI spec | ||
""" | ||
return self.openapi.load_openapi_spec() | ||
|
||
def describe_plugin(self) -> List[Document]: | ||
return self.plugin_description | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"id": "5f976f46-9d51-407e-8eeb-e46cfdd22ae1", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import openai\n", | ||
"openai.api_key = 'sk-your-key'\n", | ||
"from llama_index.agent import OpenAIAgent" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 2, | ||
"id": "538e1519-2cfe-40f4-a861-65139156d2fe", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# Load the Plugin\n", | ||
"import requests\n", | ||
"import yaml\n", | ||
"f = requests.get('https://raw.githubusercontent.com/sisbell/chatgpt-plugin-store/main/manifests/today-currency-converter.oiconma.repl.co.json').text\n", | ||
"manifest = yaml.load(f, Loader=yaml.Loader)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 3, | ||
"id": "b988f94e-6559-4404-9ba8-b41d4e4da770", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from llama_hub.tools.chatgpt_plugin.base import ChatGPTPluginToolSpec\n", | ||
"from llama_hub.tools.requests.base import RequestsToolSpec\n", | ||
"\n", | ||
"requests_spec = RequestsToolSpec()\n", | ||
"plugin_spec = ChatGPTPluginToolSpec(manifest)\n", | ||
"# OR\n", | ||
"plugin_spec = ChatGPTPluginToolSpec(manifest_url='https://raw.githubusercontent.com/sisbell/chatgpt-plugin-store/main/manifests/today-currency-converter.oiconma.repl.co.json')" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 4, | ||
"id": "475cd741-e53e-4e9c-857b-6cb52641af0d", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"agent = OpenAIAgent.from_tools([*plugin_spec.to_tool_list(), *requests_spec.to_tool_list()], verbose=True)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 5, | ||
"id": "88175b8a-0345-44d2-8b78-983d7e7415bb", | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"=== Calling Function ===\n", | ||
"Calling function: describe_plugin with args: {}\n", | ||
"Got output: \n", | ||
" 'human_description': Converts currency values based on the latest exchange rates.\n", | ||
" 'model_description': Converts currency values based on the latest exchange rates.\n", | ||
" \n", | ||
"========================\n", | ||
"The OpenAPI plugin that was loaded is a plugin that converts currency values based on the latest exchange rates. It provides functionality to retrieve exchange rates and perform currency conversions.\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(agent.chat(\"Can you give me info on the OpenAPI plugin that was loaded\"))" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 6, | ||
"id": "39e42a58-a6db-47f0-8bd7-a4c3728f0839", | ||
"metadata": {}, | ||
"outputs": [ | ||
{ | ||
"name": "stdout", | ||
"output_type": "stream", | ||
"text": [ | ||
"=== Calling Function ===\n", | ||
"Calling function: load_openapi_spec with args: {}\n", | ||
"Got output: [Document(id_='bd92f5ee-3c31-4938-a75f-004d6e451181', embedding=None, metadata={}, excluded_embed_metadata_keys=[], excluded_llm_metadata_keys=[], relationships={}, hash='b43045dea83f8c9bbefe5516329054c5ec962524078a7c9f6055af71666dd4bb', text=\"{'servers': [{'url': 'https://today-currency-converter.oiconma.repl.co/'}], 'description': 'Allows users to convert currency values based on the latest exchange rates.', 'endpoints': [('GET /currency-converter', None, {'parameters': [{'name': 'from', 'in': 'query', 'description': 'The currency to convert from', 'required': True, 'schema': {'type': 'string'}}, {'name': 'to', 'in': 'query', 'description': 'The currency to convert to', 'required': True, 'schema': {'type': 'string'}}, {'name': 'amount', 'in': 'query', 'description': 'The amount to convert', 'required': True, 'schema': {'type': 'string'}}], 'responses': {'description': 'OK', 'content': {'application/json': {'schema': {'type': 'object', 'properties': {'result': {'type': 'object', 'properties': {'info': {'type': 'object', 'properties': {'rate': {'type': 'number', 'format': 'float', 'description': 'The conversion rate between the two currencies'}}}, 'date': {'type': 'string', 'description': 'The date of the conversion'}, 'result': {'type': 'number', 'format': 'float', 'description': 'The converted amount'}}}}}}}}})]}\", start_char_idx=None, end_char_idx=None, text_template='{metadata_str}\\n\\n{content}', metadata_template='{key}: {value}', metadata_seperator='\\n')]\n", | ||
"========================\n", | ||
"=== Calling Function ===\n", | ||
"Calling function: get_request with args: {\n", | ||
" \"url\": \"https://today-currency-converter.oiconma.repl.co/currency-converter?from=EUR&to=CAD&amount=100\"\n", | ||
"}\n", | ||
"Got output: {'date': '2023-07-24', 'historical': False, 'info': {'rate': 1.469716}, 'motd': {'msg': 'If you or your company use this project or like what we doing, please consider backing us so we can continue maintaining and evolving this project.', 'url': 'https://exchangerate.host/#/donate'}, 'query': {'amount': 100, 'from': 'EUR', 'to': 'CAD'}, 'result': 146.971621, 'success': True}\n", | ||
"========================\n", | ||
"The conversion of 100 euros to CAD is 146.971621 CAD.\n" | ||
] | ||
} | ||
], | ||
"source": [ | ||
"print(agent.chat(\"Can you convert 100 euros to CAD\"))" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"id": "b11e0621-b486-4f03-8c91-b16029a928c3", | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3 (ipykernel)", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.9.12" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 5 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tag along fix because I missed adding this in the initial text to image PR