├── .gitignore ├── LICENSE ├── README.md ├── ToolGPT ├── __init__.py └── chat_gpt_with_functions.py ├── examples ├── algebra_example │ ├── algebraExample.py │ └── algebraMethods.py ├── powerpoint_example │ ├── powerpointExample.py │ └── powerpointMethods.py └── sql_example │ ├── sales.db │ ├── sales_data │ ├── sales_data.db │ ├── sqlExample.py │ └── sqlMethods.py ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | 162 | *.pptx -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [2023] [Tarun Raheja] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🛠️ ToolGPT 🤖 2 | 3 | Introducing ToolGPT, your power tool to tap into the groundbreaking function-calling abilities of OpenAI's GPT-4-0613 and GPT-3.5-turbo-0613 models! 🚀 4 | 5 | With ToolGPT, developers now have the capability to describe Python functions to the model, enabling the model to intelligently output a JSON object containing arguments to call those functions. This revolutionary feature seamlessly integrates GPT's powerful capabilities with external tools and APIs in a whole new way, offering a highly reliable method to extract structured data. 6 | 7 | What's even more exciting? The GPT models have been expertly fine-tuned to not only detect when a function needs to be called based on user's input, but also to respond with a JSON that conforms to the function's signature. This groundbreaking function calling ability makes it possible for developers to interact with the model in a structured way, effectively transforming natural language queries into executable function calls. 8 | 9 | From creating chatbots that can call external tools to answer questions, converting natural language into API calls or database queries, to extracting structured data from text - the possibilities with ToolGPT are limitless. 10 | 11 | And the icing on the cake? **All of this can be done with ANY custom Python function that you define, simply by writing a good docstring. Yes, you heard it right! You can define any Python function and run it LOCALLY on your machine without the need to share your data with OpenAI.** ToolGPT is like having an intelligent system that decides when and where to call APIs, all while ensuring the privacy and security of your data. 🛡️ 12 | 13 | Welcome to the future of AI interaction with ToolGPT! 🚀🚀 14 | 15 | 16 | ## 📥 Installation 17 | 18 | ToolGPT is as easy to install as any other Python package. Just run the following command: 19 | 20 | ``` 21 | pip install ToolGPT 22 | ``` 23 | 24 | ## 🏃‍♀️ Quickstart 25 | 26 | Once you have ToolGPT installed, you can use it as follows: 27 | 28 | ``` 29 | from ToolGPT import ChatGPTWithFunctions 30 | 31 | # Define your functions with good docstrings in NumpyCode format 32 | def add(a, b): 33 | """ 34 | Adds Two Numbers 35 | 36 | Parameters 37 | ---------- 38 | a : integer 39 | number to be added 40 | b : integer 41 | number to be added 42 | 43 | Returns 44 | ------- 45 | integer 46 | sum 47 | """ 48 | return a + b 49 | 50 | 51 | # Instantiate the class 52 | wrapper = ChatGPTWithFunctions() 53 | 54 | # Define a prompt 55 | prompt = "What is five plus ten?" 56 | 57 | # Use the chatbot 58 | ans = wrapper.prompt_with_functions(prompt, [add]) 59 | print(ans) 60 | ``` 61 | 62 | ## 🎉 Cool Examples 🚀 63 | 64 | ToolGPT isn't just about chat – it's about supercharging chat with the power of function calls! Let's have a look at two exciting examples that demonstrate ToolGPT's capabilities to a whole new level: 65 | 66 | ### 🧮 Algebra Capabilities (algebra_example) 🤓 67 | 68 | Ever wished your chatbot could solve algebraic equations? Now it can! With ToolGPT, you can make ChatGPT solve math problems by leveraging the power of Python functions. Check out the `algebra_example` directory for an enlightening example: 69 | 70 | ``` 71 | ├── algebra_example 72 | │ ├── algebraExample.py 73 | │ └── algebraMethods.py 74 | ``` 75 | 76 | In this example, the `algebraMethods.py` file contains custom Python functions for solving algebraic problems. The `algebraExample.py` file showcases how ToolGPT uses these functions to add algebraic capabilities to a chatbot. Run the `algebraExample.py` to see how ChatGPT can now solve math problems for you! 77 | 78 | ### 🎙️ PowerPoint Presentation Capabilities (powerpoint_example) 🖥️ 79 | 80 | Yes, you read that right. ToolGPT can even help in automating the creation of PowerPoint presentations! 🎉 81 | 82 | Explore the `powerpoint_example` directory for an example that's worth a thousand slides: 83 | 84 | ``` 85 | ├── powerpoint_example 86 | │ ├── powerpointExample.py 87 | │ └── powerpointMethods.py 88 | ``` 89 | 90 | 91 | In this example, `powerpointMethods.py` contains Python functions that interact with Microsoft's PowerPoint application. The `powerpointExample.py` file demonstrates how ToolGPT uses these functions to create PowerPoint presentations based on user instructions. With this, creating PowerPoint presentations is as easy as chatting! 92 | 93 | With ToolGPT, the possibilities are endless. Create more Python functions, and ToolGPT will help you incorporate them into your chatbot. It's like having a chatbot on steroids, all in the comfort of your Python environment! 94 | 95 | ### 🗄️ SQL Example: Interacting with a SQLite Database 📊 96 | 97 | This cool example showcases the ability of ToolGPT to interact with a SQLite database, performing queries and returning meaningful results. 🎉 98 | 99 | The SQLite example is located in the `sql_example` directory. The directory structure is as follows: 100 | 101 | ``` 102 | ├── sql_example 103 | │ ├── sqlExample.py 104 | │ └── sqlMethods.py 105 | ``` 106 | 107 | - `sqlMethods.py`: This file contains the Python functions that interact with the SQLite database. 108 | 109 | - `sqlExample.py`: This is the main script you'll run. It utilizes `sqlMethods.py` and integrates those functions with ToolGPT. 110 | 111 | - `sales_data.db`: This is a SQLite database populated with some sample sales data. The database is setup and populated using the `setup_database` function in the `sqlMethods.py` file. 112 | 113 | 114 | ## 📚 Documentation 115 | 116 | You can find more detailed documentation in the code itself! 117 | 118 | ## 🌐 Contribute 119 | 120 | We welcome contributions from the community! If you'd like to contribute, please fork the repository and submit a pull request. 121 | 122 | ## 📄 License 123 | 124 | ToolGPT is licensed under the MIT license. For more details, see [LICENSE](./LICENSE). 125 | 126 | ## ⭐ Star us on GitHub 127 | 128 | If you find this package useful, please consider starring us on GitHub! 129 | 130 | Happy coding! 🚀🚀 131 | -------------------------------------------------------------------------------- /ToolGPT/__init__.py: -------------------------------------------------------------------------------- 1 | from .chat_gpt_with_functions import ChatGPTWithFunctions -------------------------------------------------------------------------------- /ToolGPT/chat_gpt_with_functions.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import re 3 | import openai 4 | import json 5 | 6 | class ChatGPTWithFunctions: 7 | """ 8 | A class that encapsulates the interaction with OpenAI GPT-3 with functions 9 | """ 10 | def __init__(self, model="gpt-3.5-turbo-0613"): 11 | """ 12 | Constructor for ChatGPTWithFunctions class 13 | 14 | Parameters 15 | ---------- 16 | model : str, optional 17 | The OpenAI GPT model to use. Defaults to "gpt-3.5-turbo-0613". 18 | """ 19 | self.model = model 20 | 21 | @staticmethod 22 | def parse_docstring(function): 23 | """ 24 | Parse the docstring of a function to extract function name, description and parameters. 25 | 26 | Parameters 27 | ---------- 28 | function : Callable 29 | The function whose docstring is to be parsed. 30 | 31 | Returns 32 | ------- 33 | dict 34 | A dictionary with the function's name, description, and parameters. 35 | """ 36 | doc = inspect.getdoc(function) 37 | 38 | # Find function description 39 | function_description = re.search(r'(.*?)Parameters', doc, re.DOTALL).group(1).strip() 40 | 41 | # Find parameter descriptions 42 | parameters_description = re.findall(r'(\w+)\s*:\s*(\w+)\n(.*?)(?=\n\w+\s*:\s*|\nReturns|$)', doc, re.DOTALL) 43 | 44 | # Get the parameters from the function signature 45 | signature_params = list(inspect.signature(function).parameters.keys()) 46 | 47 | # Construct the parameters dictionary 48 | properties = {} 49 | required = [] 50 | for name, type, description in parameters_description: 51 | name = name.strip() 52 | type = type.strip() 53 | description = description.strip() 54 | 55 | required.append(name) 56 | properties[name] = { 57 | "type": type, 58 | "description": description, 59 | } 60 | 61 | # Check if the number of parameters match 62 | if len(signature_params) != len(required): 63 | raise ValueError(f"Number of parameters in function signature ({len(signature_params)}) does not match the number of parameters in docstring ({len(required)})") 64 | 65 | # Check if each parameter in the signature has a docstring 66 | for param in signature_params: 67 | if param not in required: 68 | raise ValueError(f"Parameter '{param}' in function signature is missing in the docstring") 69 | 70 | parameters = { 71 | "type": "object", 72 | "properties": properties, 73 | "required": required, 74 | } 75 | 76 | # Construct the function dictionary 77 | function_dict = { 78 | "name": function.__name__, 79 | "description": function_description, 80 | "parameters": parameters, 81 | } 82 | 83 | return function_dict 84 | 85 | @staticmethod 86 | def get_role_message_dict(role, content=None, fn_name=None, arguments=None, result=None): 87 | """ 88 | Get message dicts for different roles. 89 | 90 | Parameters 91 | ---------- 92 | role : str 93 | The role of the user. 94 | content : str, optional 95 | The content of the message. Defaults to None. 96 | fn_name : str, optional 97 | The name of the function. Defaults to None. 98 | arguments : dict, optional 99 | The arguments for the function. Defaults to None. 100 | result : Any, optional 101 | The result of the function. Defaults to None. 102 | 103 | Returns 104 | ------- 105 | dict 106 | The dictionary with the role, content, function name, arguments, and result. 107 | """ 108 | message_dict = {"role":role} 109 | if role == "user": 110 | message_dict["content"] = content 111 | elif role == "assistant": 112 | message_dict["content"] = content 113 | message_dict["function_call"] = {} 114 | message_dict["function_call"]["name"] = fn_name 115 | message_dict["function_call"]["arguments"] = arguments 116 | elif role == "function": 117 | message_dict["name"] = fn_name 118 | message_dict["content"] = f'{{"result": {str(result)} }}' 119 | return message_dict 120 | 121 | def run_with_functions(self, messages, function_dicts): 122 | """ 123 | Gets the ChatGPT completion based on list of given function_dicts. 124 | 125 | Parameters 126 | ---------- 127 | messages : list 128 | List of message dictionaries. 129 | function_dicts : list 130 | List of function dictionaries. 131 | 132 | Returns 133 | ------- 134 | OpenAI.ChatCompletion 135 | The response from ChatCompletion API. 136 | """ 137 | response = openai.ChatCompletion.create( 138 | model=self.model, 139 | messages=messages, 140 | functions=function_dicts, 141 | temperature=0, 142 | ) 143 | return response 144 | 145 | def prompt_with_functions(self, prompt, functions): 146 | """ 147 | Runs the prompt with given functions. 148 | 149 | Parameters 150 | ---------- 151 | prompt : str 152 | The prompt to be used with the GPT model. 153 | functions : list 154 | List of functions to be used with the GPT model. 155 | """ 156 | print(prompt) 157 | fn_names_dict = {} 158 | for fn in functions: 159 | fn_names_dict[fn.__name__] = fn 160 | function_dicts = [self.parse_docstring(fun) for fun in functions] 161 | messages = [self.get_role_message_dict("user", content=(prompt))] 162 | 163 | while True: 164 | response = self.run_with_functions(messages, function_dicts) 165 | 166 | if response.choices[0]["finish_reason"] == "stop": 167 | print(response.choices[0]["message"]["content"]) 168 | print("Received STOP signal") 169 | break 170 | 171 | elif response.choices[0]["finish_reason"] == "function_call": 172 | print("Received FUNCTION_CALL signal") 173 | fn_name = response.choices[0].message["function_call"].name 174 | arguments = response.choices[0].message["function_call"].arguments 175 | print(arguments) 176 | json_arguments = json.loads(arguments) 177 | function = fn_names_dict[fn_name] 178 | result = function(**json_arguments) 179 | messages.append(self.get_role_message_dict("assistant", fn_name=fn_name, arguments=arguments)) 180 | messages.append(self.get_role_message_dict("function", fn_name=fn_name, result=result)) 181 | response = self.run_with_functions(messages, function_dicts) 182 | -------------------------------------------------------------------------------- /examples/algebra_example/algebraExample.py: -------------------------------------------------------------------------------- 1 | from ToolGPT import ChatGPTWithFunctions 2 | 3 | import os 4 | import openai 5 | from dotenv import load_dotenv 6 | from algebraMethods import add, mul, sub 7 | 8 | load_dotenv() 9 | openai.api_key = os.getenv("OPENAI_API_KEY") 10 | prompt = "What is five plus ten minus fifteen times two?" 11 | wrapper = ChatGPTWithFunctions() 12 | ans = wrapper.prompt_with_functions(prompt, [add, sub, mul]) 13 | print(ans) -------------------------------------------------------------------------------- /examples/algebra_example/algebraMethods.py: -------------------------------------------------------------------------------- 1 | 2 | def add(a, b): 3 | """ 4 | Adds Two Numbers 5 | 6 | Parameters 7 | ---------- 8 | a : integer 9 | number to be added 10 | b : integer 11 | number to be added 12 | 13 | Returns 14 | ------- 15 | integer 16 | sum 17 | """ 18 | return a + b 19 | 20 | def sub(a, b): 21 | """ 22 | Subs Two Numbers 23 | 24 | Parameters 25 | ---------- 26 | a : integer 27 | number to be subbed 28 | b : integer 29 | number to be subbed 30 | 31 | Returns 32 | ------- 33 | int 34 | sub 35 | """ 36 | return a - b 37 | 38 | def mul(a, b): 39 | """ 40 | Muls Two Numbers 41 | 42 | Parameters 43 | ---------- 44 | a : integer 45 | number to be muled 46 | b : integer 47 | number to be muled 48 | 49 | Returns 50 | ------- 51 | int 52 | mul 53 | """ 54 | return a * b -------------------------------------------------------------------------------- /examples/powerpoint_example/powerpointExample.py: -------------------------------------------------------------------------------- 1 | from ToolGPT import ChatGPTWithFunctions 2 | 3 | import os 4 | import openai 5 | from dotenv import load_dotenv 6 | from powerpointMethods import create_presentation, add_slide_with_bullets 7 | 8 | load_dotenv() 9 | openai.api_key = os.getenv("OPENAI_API_KEY") 10 | prompt = "Make a 5 page presentation about bananas." 11 | wrapper = ChatGPTWithFunctions() 12 | ans = wrapper.prompt_with_functions(prompt, [create_presentation, add_slide_with_bullets]) 13 | print(ans) -------------------------------------------------------------------------------- /examples/powerpoint_example/powerpointMethods.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import collections.abc 3 | 4 | from pptx import Presentation 5 | from pptx.util import Inches, Pt 6 | from pptx.enum.text import MSO_ANCHOR, MSO_AUTO_SIZE, PP_ALIGN 7 | from pptx.dml.color import RGBColor 8 | 9 | def create_presentation(filename): 10 | """ 11 | Creates a new PowerPoint presentation 12 | 13 | Parameters 14 | ---------- 15 | filename : string 16 | The name of the PowerPoint file to be created 17 | 18 | Returns 19 | ------- 20 | idk 21 | """ 22 | prs = Presentation() 23 | prs.save(filename) 24 | print(f"Presentation '{filename}' created.") 25 | 26 | def add_slide_with_bullets(filename, title, bullet_points_text): 27 | """ 28 | Adds a slide with bullet points to an existing PowerPoint presentation 29 | 30 | Parameters 31 | ---------- 32 | filename : string 33 | The name of the PowerPoint file to add a slide to 34 | title : string 35 | The title of the slide 36 | bullet_points_text : string 37 | The bullet points for the slide, separated by newline 38 | 39 | Returns 40 | ------- 41 | idk 42 | """ 43 | bullet_points = bullet_points_text.split("\\n") 44 | bullet_points = [elem.strip() for elem in bullet_points] 45 | prs = Presentation(filename) 46 | 47 | slide_layout = prs.slide_layouts[5] # blank slide 48 | slide = prs.slides.add_slide(slide_layout) 49 | 50 | # define title box 51 | left = Inches(0.5) 52 | top = Inches(0.5) 53 | width = Inches(9) 54 | height = Inches(1) 55 | 56 | txBox = slide.shapes.add_textbox(left, top, width, height) 57 | tf = txBox.text_frame 58 | tf.word_wrap = True 59 | tf.auto_size = MSO_AUTO_SIZE.SHAPE_TO_FIT_TEXT 60 | tf.text_anchor = MSO_ANCHOR.MIDDLE 61 | 62 | p = tf.add_paragraph() 63 | p.text = title 64 | p.font.bold = True 65 | p.font.size = Pt(36) 66 | p.font.color.rgb = RGBColor(0x00, 0x00, 0x80) # Dark blue color 67 | p.alignment = PP_ALIGN.CENTER 68 | 69 | # define content box with bullet points 70 | left = Inches(1) 71 | top = Inches(2) 72 | width = Inches(8.5) 73 | height = Inches(5) 74 | 75 | txBox = slide.shapes.add_textbox(left, top, width, height) 76 | tf = txBox.text_frame 77 | tf.word_wrap = True 78 | 79 | for point in bullet_points: 80 | p = tf.add_paragraph() 81 | p.text = point 82 | p.level = 0 # making the text a bullet point 83 | p.font.size = Pt(24) 84 | p.font.color.rgb = RGBColor(0x80, 0x80, 0x80) # Grey color 85 | 86 | prs.save(filename) 87 | print(f"Slide added to the presentation '{filename}'.") -------------------------------------------------------------------------------- /examples/sql_example/sales.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tehruhn/ToolGPT/252661e0a3734f9ace3098a5134e9e9fd9a277b6/examples/sql_example/sales.db -------------------------------------------------------------------------------- /examples/sql_example/sales_data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tehruhn/ToolGPT/252661e0a3734f9ace3098a5134e9e9fd9a277b6/examples/sql_example/sales_data -------------------------------------------------------------------------------- /examples/sql_example/sales_data.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tehruhn/ToolGPT/252661e0a3734f9ace3098a5134e9e9fd9a277b6/examples/sql_example/sales_data.db -------------------------------------------------------------------------------- /examples/sql_example/sqlExample.py: -------------------------------------------------------------------------------- 1 | from ToolGPT import ChatGPTWithFunctions 2 | 3 | import os 4 | import openai 5 | from dotenv import load_dotenv 6 | from sqlMethods import get_max_sale, get_top_rows, setup_database 7 | 8 | load_dotenv() 9 | openai.api_key = os.getenv("OPENAI_API_KEY") 10 | # # Uncomment this to make the table 11 | # setup_database() 12 | prompt = "What is the Max Sale? My table is sales_data.db" 13 | wrapper = ChatGPTWithFunctions() 14 | ans = wrapper.prompt_with_functions(prompt, [get_max_sale, get_top_rows]) 15 | print(ans) -------------------------------------------------------------------------------- /examples/sql_example/sqlMethods.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | from typing import List, Any, Tuple 3 | 4 | def get_max_sale(database: str = 'sales_data.db') -> Tuple[str, str, int, float]: 5 | """ 6 | Function to get the row with maximum sales quantity. 7 | 8 | Parameters 9 | ---------- 10 | database : string 11 | The name of the SQLite database. 12 | 13 | Returns 14 | ------- 15 | max_sale : Tuple[str, str, int, float] 16 | The row with maximum sales quantity. 17 | """ 18 | # Connect to the SQLite database 19 | conn = sqlite3.connect(database) 20 | 21 | # Create a cursor object 22 | c = conn.cursor() 23 | 24 | # Execute the query 25 | c.execute('SELECT * FROM sales ORDER BY quantity DESC LIMIT 1') 26 | 27 | # Fetch the result 28 | max_sale = c.fetchone() 29 | 30 | # Close the connection 31 | conn.close() 32 | 33 | return max_sale 34 | 35 | 36 | def get_top_rows(column: str, database: str = 'sales_data.db', limit: int = 5) -> List[Tuple[str, str, int, float]]: 37 | """ 38 | Function to get the top rows sorted by a particular column. 39 | 40 | Parameters 41 | ---------- 42 | column : string 43 | The column to sort by. 44 | database : string 45 | The name of the SQLite database. 46 | limit : integer 47 | The number of rows to return. 48 | 49 | Returns 50 | ------- 51 | top_rows : List[Tuple[str, str, int, float]] 52 | The top rows sorted by the given column. 53 | """ 54 | # Connect to the SQLite database 55 | conn = sqlite3.connect(database) 56 | 57 | # Create a cursor object 58 | c = conn.cursor() 59 | 60 | # Execute the query 61 | c.execute(f'SELECT * FROM sales ORDER BY {column} DESC LIMIT ?', (limit,)) 62 | 63 | # Fetch the result 64 | top_rows = c.fetchall() 65 | 66 | # Close the connection 67 | conn.close() 68 | 69 | return top_rows 70 | 71 | 72 | def setup_database(database: str = 'sales_data.db') -> None: 73 | """ 74 | Function to setup the SQLite database and populate it with sample sales data. 75 | 76 | Parameters 77 | ---------- 78 | database : string 79 | The name of the SQLite database. 80 | """ 81 | 82 | # Connect to the SQLite database 83 | conn = sqlite3.connect(database) 84 | 85 | # Create a cursor object 86 | c = conn.cursor() 87 | 88 | # Create table 89 | c.execute('''CREATE TABLE sales 90 | (name text, product text, quantity integer, price real)''') 91 | 92 | # Insert a row of data 93 | sales_data = [ 94 | ('John', 'Apples', 10, 1.25), 95 | ('Sarah', 'Bananas', 20, 0.75), 96 | ('Dave', 'Oranges', 30, 0.80), 97 | ('Lisa', 'Pears', 15, 1.50), 98 | ('Mike', 'Grapes', 40, 2.00), 99 | ('Mary', 'Cherries', 50, 3.00), 100 | ('Anne', 'Pineapples', 60, 1.75), 101 | ('Paul', 'Mangoes', 70, 2.25), 102 | ('Olivia', 'Peaches', 80, 1.00), 103 | ('Nick', 'Pomegranates', 90, 2.50) 104 | ] 105 | 106 | c.executemany('INSERT INTO sales VALUES (?,?,?,?)', sales_data) 107 | 108 | # Save (commit) the changes 109 | conn.commit() 110 | 111 | # Close the connection 112 | conn.close() 113 | 114 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | openai 2 | python-pptx 3 | python-dotenv -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='ToolGPT', 5 | version='0.0.1', 6 | url='https://github.com/tehruhn/ToolGPT', 7 | author='Tarun Raheja', 8 | author_email='tarunraheja1234@gmail.com', 9 | description='Package to interface Python functions with ChatGPT', 10 | packages=find_packages(), 11 | install_requires=['openai'], 12 | ) 13 | --------------------------------------------------------------------------------