├── .gitignore ├── LICENSE ├── README.md ├── docker ├── Dockerfile ├── build_docker.sh ├── local_run_docker.sh ├── local_run_docker_notebook.sh └── start_notebook.sh ├── images ├── openmldb_chatgpt_cli.png ├── prompt1-1.png ├── prompt1.png ├── prompt2-1.png ├── prompt2-2.png ├── prompt2.png ├── prompt3.png ├── prompt4.png ├── prompt5.png └── prompt6.png ├── openmldb_chatgpt ├── __init__.py ├── cli.py ├── config_util.py ├── gpt_manager.py ├── help_util.py ├── history.txt ├── openmldb_manager.py ├── print_util.py └── sql_util.py ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Autocomplete files 3 | openmldb-chatgpt/history.txt 4 | 5 | # IDE files 6 | .idea/ 7 | 8 | # Mac files 9 | .DS_Store 10 | 11 | # Byte-compiled / optimized / DLL files 12 | __pycache__/ 13 | *.py[cod] 14 | *$py.class 15 | 16 | # C extensions 17 | *.so 18 | 19 | # Distribution / packaging 20 | .Python 21 | env/ 22 | build/ 23 | develop-eggs/ 24 | dist/ 25 | downloads/ 26 | eggs/ 27 | .eggs/ 28 | lib/ 29 | lib64/ 30 | parts/ 31 | sdist/ 32 | var/ 33 | wheels/ 34 | *.egg-info/ 35 | .installed.cfg 36 | *.egg 37 | 38 | # PyInstaller 39 | # Usually these files are written by a python script from a template 40 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 41 | *.manifest 42 | *.spec 43 | 44 | # Installer logs 45 | pip-log.txt 46 | pip-delete-this-directory.txt 47 | 48 | # Unit test / coverage reports 49 | htmlcov/ 50 | .tox/ 51 | .coverage 52 | .coverage.* 53 | .cache 54 | nosetests.xml 55 | coverage.xml 56 | *.cover 57 | .hypothesis/ 58 | 59 | # Translations 60 | *.mo 61 | *.pot 62 | 63 | # Django stuff: 64 | *.log 65 | local_settings.py 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | target/ 79 | 80 | # Jupyter Notebook 81 | .ipynb_checkpoints 82 | 83 | # pyenv 84 | .python-version 85 | 86 | # celery beat schedule file 87 | celerybeat-schedule 88 | 89 | # SageMath parsed files 90 | *.sage.py 91 | 92 | # dotenv 93 | .env 94 | 95 | # virtualenv 96 | .venv 97 | venv/ 98 | ENV/ 99 | 100 | # Spyder project settings 101 | .spyderproject 102 | .spyproject 103 | 104 | # Rope project settings 105 | .ropeproject 106 | 107 | # mkdocs documentation 108 | /site 109 | 110 | # mypy 111 | .mypy_cache/ 112 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenMLDB ChatGPT Plugin 2 | 3 | The ChatGPT plugin to enhance OpenMLDB. Here are the features: 4 | 5 | * Integrate **GPT models** with OpenMLDB service 6 | * Automatically **generate SQL** and **correct SQL** 7 | * Enable to update database with **chat interface** 8 | * New using experience of database with **AI prompts** 9 | 10 | ## Install 11 | 12 | Install with [python package](https://pypi.org/project/openmldb-chatgpt/). 13 | 14 | ``` 15 | pip install openmldb-chatgpt 16 | ``` 17 | 18 | Use pre-built docker image (OpenMLDB included). 19 | 20 | ``` 21 | docker run -it tobegit3hub/openmldb-chatgpt 22 | ``` 23 | 24 | ## Usage 25 | 26 | Install [OpenMLDB](https://github.com/4paradigm/OpenMLDB) with [PortableOpenMLDB](https://github.com/tobegit3hub/PortableOpenMLDB). No need to install for docker container. 27 | 28 | Register [OpenAI account](https://openai.com) and get the API key. Make sure you can access the OpenAI API. 29 | 30 | Run `openmldb-chatgpt` to connect with OpenMLDB and use OpenAI API key. 31 | 32 | ![](./images/openmldb_chatgpt_cli.png) 33 | 34 | ## Prompts 35 | 36 | For beginners, AI model can teach you how to use OpenMLDB and database. 37 | 38 | ![](images/prompt1.png) 39 | 40 | ![](images/prompt1-1.png) 41 | 42 | All the SQL will be executed in OpenMLDB and explained by AI model. 43 | 44 | ![](images/prompt2.png) 45 | 46 | ![](images/prompt2-1.png) 47 | 48 | ![](images/prompt2-2.png) 49 | 50 | If you create a little more complicated table, AI model will try to understand the meaning with your input. 51 | 52 | ![](images/prompt3.png) 53 | 54 | For senior SQL users, AI model can help to debug and correct your SQL. 55 | 56 | ![](images/prompt4.png) 57 | 58 | AI model can help to analyse the complex SQL and explain it in natural language as well. 59 | 60 | ![](images/prompt5.png) 61 | 62 | You can ask AI model to show more info about OpenMLDB cluster without writing specified SQL. 63 | 64 | ![](images/prompt6.png) 65 | 66 | **Please try by yourself and discover more magic functions with the powerful AI model and OpenMLDB!** 67 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM tobegit3hub/portable-openmldb 2 | 3 | RUN pip install openmldb-chatgpt 4 | RUN pip install notebook 5 | 6 | ADD start_notebook.sh ./ 7 | 8 | CMD ["bash", "-c", "./start.sh && openmldb-chatgpt"] 9 | -------------------------------------------------------------------------------- /docker/build_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker build -t tobegit3hub/openmldb-chatgpt . 4 | -------------------------------------------------------------------------------- /docker/local_run_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run -it tobegit3hub/openmldb-chatgpt 4 | -------------------------------------------------------------------------------- /docker/local_run_docker_notebook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run -it -p 8888:8888 tobegit3hub/openmldb-chatgpt ./start_notebook.sh 4 | -------------------------------------------------------------------------------- /docker/start_notebook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | jupyter notebook --allow-root --ip 0.0.0.0 --port 8888 --NotebookApp.token='' --NotebookApp.password='' 4 | -------------------------------------------------------------------------------- /images/openmldb_chatgpt_cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/openmldb_chatgpt_cli.png -------------------------------------------------------------------------------- /images/prompt1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt1-1.png -------------------------------------------------------------------------------- /images/prompt1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt1.png -------------------------------------------------------------------------------- /images/prompt2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt2-1.png -------------------------------------------------------------------------------- /images/prompt2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt2-2.png -------------------------------------------------------------------------------- /images/prompt2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt2.png -------------------------------------------------------------------------------- /images/prompt3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt3.png -------------------------------------------------------------------------------- /images/prompt4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt4.png -------------------------------------------------------------------------------- /images/prompt5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt5.png -------------------------------------------------------------------------------- /images/prompt6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tobegit3hub/openmldb-chatgpt-plugin/4de32dde0e585396e0b5109b2f1e214ad6380082/images/prompt6.png -------------------------------------------------------------------------------- /openmldb_chatgpt/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | -------------------------------------------------------------------------------- /openmldb_chatgpt/cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2023 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import os 18 | import sys 19 | sys.path.append(os.path.join(os.path.dirname(__file__), '.')) 20 | 21 | import logging 22 | logging.basicConfig(level=logging.INFO) 23 | logger = logging.getLogger(__name__) 24 | 25 | from prompt_toolkit import PromptSession 26 | from prompt_toolkit.auto_suggest import AutoSuggestFromHistory 27 | from prompt_toolkit.completion import WordCompleter 28 | from prompt_toolkit.history import FileHistory 29 | from prompt_toolkit.styles import Style 30 | 31 | from print_util import PrintUtil 32 | from sql_util import SqlUtil 33 | from config_util import ConfigUtil 34 | from openmldb_manager import OpenmldbManager 35 | from gpt_manager import GptManager 36 | from help_util import HelpUtil 37 | 38 | 39 | def main(): 40 | # Load config from config file 41 | config = ConfigUtil().config 42 | 43 | # Init cli parameters 44 | history_file_path = os.path.join(os.path.expanduser("~"), ".openmldb/", "history.txt") 45 | cli_session = PromptSession(history=FileHistory(history_file_path), auto_suggest=AutoSuggestFromHistory()) 46 | cli_completer = WordCompleter(SqlUtil.autocomplete_keywords(), ignore_case=True) 47 | cli_style = Style.from_dict({ 48 | '': '#ff00ff', 49 | }) 50 | 51 | 52 | # Connect with OpenMLDB 53 | openmldb_manager = OpenmldbManager(config.get("OpenMLDB", "zk_cluster"), config.get("OpenMLDB", "zk_root_path")) 54 | 55 | # Connect with OpenAI API key 56 | gpt_manager = GptManager(config.get("OpenAI", "api_key"), config.get("OpenAI", "model_engine"), int(config.get("OpenAI", "max_tokens")), openmldb_manager) 57 | 58 | # Print help message 59 | HelpUtil.print_help_message() 60 | 61 | 62 | def wait_and_handle(): 63 | # Get user command 64 | user_input = cli_session.prompt('USER > ', completer=cli_completer, style=cli_style) 65 | 66 | if user_input == "": 67 | return 68 | 69 | # Quit command 70 | if user_input.lower() == 'q' or user_input.lower() == 'quit' or user_input.lower() == 'exit': 71 | sys.exit(0) 72 | 73 | # Help command 74 | elif user_input.lower() == "help": 75 | HelpUtil.print_help_message() 76 | 77 | else: 78 | # Run SQL 79 | if SqlUtil.is_possible_sql(user_input): 80 | # Run OpenMLDB SQL 81 | is_success = openmldb_manager.run_openmldb_sql(user_input) 82 | 83 | if is_success: 84 | # Use GPT to anaylse SQL 85 | gpt_prompt = f"分析成功执行的SQL语句'{user_input}'" 86 | PrintUtil.gpt_print(gpt_prompt) 87 | gpt_manager.run_gpt(gpt_prompt, update_history_message=False) 88 | 89 | # Use GPT to suggest next step 90 | gpt_prompt = f"执行完SQL语句'{user_input}',然后建议执行什么操作" 91 | PrintUtil.gpt_print(gpt_prompt) 92 | gpt_manager.run_gpt(gpt_prompt, update_history_message=False) 93 | else: 94 | # Use GPT to anaylse the error message 95 | gpt_prompt = f"分析SQL失败原因,SQL语句是'{user_input}',错误信息是'{openmldb_manager.last_sql_error_message}'" 96 | PrintUtil.gpt_print(gpt_prompt) 97 | gpt_manager.run_gpt(gpt_prompt, update_history_message=False) 98 | 99 | # Chat with GPT 100 | else: 101 | gpt_manager.run_gpt(user_input) 102 | 103 | while True: 104 | try: 105 | wait_and_handle() 106 | except KeyboardInterrupt: 107 | pass 108 | 109 | # Close OpenMLDB connection 110 | openmldb_manager.close() 111 | 112 | 113 | if __name__ == "__main__": 114 | main() 115 | -------------------------------------------------------------------------------- /openmldb_chatgpt/config_util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import configparser 17 | import getpass 18 | import copy 19 | import logging 20 | logger = logging.getLogger(__name__) 21 | 22 | 23 | class ConfigUtil: 24 | 25 | def __init__(self): 26 | self.config_file_path = os.path.join(os.path.expanduser("~"), ".openmldb/", "openmldb-chatgpt.ini") 27 | self.config = configparser.ConfigParser() 28 | self.init_config() 29 | self.print_config() 30 | 31 | @staticmethod 32 | def use_default_value(text: str) -> bool: 33 | if text == "" or text.lower() == "y" or text.lower() == "yes": 34 | return True 35 | else: 36 | return False 37 | 38 | @staticmethod 39 | def print_config_parser(config): 40 | # Print the contents of the ConfigParser object 41 | for section in config.sections(): 42 | print(f"[{section}]") 43 | for option in config.options(section): 44 | value = config.get(section, option) 45 | print(f"{option} = {value}") 46 | 47 | def init_config(self): 48 | # Create directory if not exists 49 | config_directory = os.path.join(os.path.expanduser("~"), ".openmldb/") 50 | if not os.path.exists(config_directory): 51 | os.makedirs(config_directory) 52 | logger.info(f"Create the directory of {config_directory}") 53 | 54 | self.config.read(self.config_file_path) 55 | 56 | if not self.config.has_section("OpenAI"): 57 | self.config.add_section("OpenAI") 58 | 59 | if not self.config.has_option("OpenAI", "api_key"): 60 | self.config.set("OpenAI", "api_key", getpass.getpass("Please input your OpenAI API Key (sk-xxx): ")) 61 | 62 | if not self.config.has_option("OpenAI", "model_engine"): 63 | text = input("Please choose GPT model_engine (y/yes for default gpt-3.5-turbo): ") 64 | if ConfigUtil.use_default_value(text): 65 | self.config.set("OpenAI", "model_engine", "gpt-3.5-turbo") 66 | else: 67 | self.config.set("OpenAI", "model_engine", text) 68 | 69 | if not self.config.has_option("OpenAI", "max_tokens"): 70 | text = input("Please choose GPT max_tokens (y/yes for default 256): ") 71 | if ConfigUtil.use_default_value(text): 72 | self.config.set("OpenAI", "max_tokens", "256") 73 | else: 74 | self.config.set("OpenAI", "max_tokens", text) 75 | 76 | if not self.config.has_section("OpenMLDB"): 77 | self.config.add_section("OpenMLDB") 78 | 79 | if not self.config.has_option("OpenMLDB", "zk_cluster"): 80 | text = input("Please choose OpenMLDB zk_cluster (y/yes for default 0.0.0.0:2181): ") 81 | if ConfigUtil.use_default_value(text): 82 | self.config.set("OpenMLDB", "zk_cluster", "0.0.0.0:2181") 83 | else: 84 | self.config.set("OpenMLDB", "zk_cluster", text) 85 | 86 | if not self.config.has_option("OpenMLDB", "zk_root_path"): 87 | text = input("Please choose OpenMLDB zk_root_path (y/yes for default /openmldb): ") 88 | if ConfigUtil.use_default_value(text): 89 | self.config.set("OpenMLDB", "zk_root_path", "/openmldb") 90 | else: 91 | self.config.set("OpenMLDB", "zk_root_path", text) 92 | 93 | with open(self.config_file_path, "w") as config_file: 94 | self.config.write(config_file) 95 | 96 | def print_config(self): 97 | logger.info(f"Please check config in {self.config_file_path}") 98 | 99 | safe_config = copy.deepcopy(self.config) 100 | safe_config.set("OpenAI", "api_key", "[Hide the OpenAI API Key]") 101 | ConfigUtil.print_config_parser(safe_config) 102 | -------------------------------------------------------------------------------- /openmldb_chatgpt/gpt_manager.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import openai 16 | from collections import deque 17 | 18 | from print_util import PrintUtil 19 | from openmldb_manager import OpenmldbManager 20 | 21 | import logging 22 | logger = logging.getLogger(__name__) 23 | 24 | 25 | class GptManager: 26 | 27 | def __init__(self, api_key: str, model_engine: str, max_tokens: int, openmldb_manager: OpenmldbManager): 28 | # Set the OpenAI API key 29 | openai.api_key = api_key 30 | 31 | self.model_engine = model_engine 32 | self.max_tokens = max_tokens 33 | 34 | # Keep the history messages 35 | HISTORY_MESSAGE_SIZE = 6 36 | self.history_message_queue = deque(maxlen=HISTORY_MESSAGE_SIZE) 37 | 38 | # Generate the system role prompt 39 | system_role_prompt = GptManager.construct_system_role_prompt(openmldb_manager) 40 | logger.info(f"Use system role promet: {system_role_prompt}") 41 | self.system_message = {"role": "system", "content": system_role_prompt} 42 | 43 | @staticmethod 44 | def construct_system_role_prompt(openmldb_manager: OpenmldbManager) -> str: 45 | # The example system role prompt 46 | """ 47 | You are a helpful assistant and database expert. You are using OpenMLDB database and teach users how to use SQL. 48 | 49 | OpenMLDB has 3 databases including "db1", "school", "fin tect". 50 | 51 | SQL tables and their attributes: 52 | # db1.t1 (col1) 53 | # school.student (id, name, age) 54 | # school.teacher (id, name, subject) 55 | # fin_tect.bank (id, name, department_id) 56 | # fin_tect.user (id, name, address) 57 | # fin_tect.trade (id, employee_id, amount, date) 58 | """ 59 | 60 | db_names = openmldb_manager.get_database_names() 61 | db_num = len(db_names) 62 | db_names_string = ",".join(db_names) 63 | table_attributes = openmldb_manager.get_all_table_info(db_names) 64 | 65 | if db_num > 0: 66 | system_role_prompt = f"""You are a helpful assistant and database expert. You are using OpenMLDB database and teach users how to use SQL. 67 | 68 | OpenMLDB has {db_num} databases including {db_names_string}. 69 | 70 | SQL tables and their attributes: 71 | {table_attributes}""" 72 | else: 73 | system_role_prompt = f"You are a helpful assistant and database expert. You are using OpenMLDB database and teach users how to use SQL." 74 | 75 | return system_role_prompt 76 | 77 | def run_gpt(self, prompt: str, update_history_message: bool = True): 78 | """ 79 | Run GPT model with prompt. 80 | 81 | :param prompt The string to request GPT model. 82 | :update_history_message We should add the request and response message in history messages or not 83 | """ 84 | 85 | # 1. Add the user prompt in messages 86 | self.history_message_queue.append({"role": "user", "content": prompt}) 87 | 88 | # 2. Copy the history messages and add the system role prompt in the head of list 89 | request_messages = list(self.history_message_queue) 90 | request_messages.insert(0, self.system_message) 91 | 92 | # 3. Request OpenAI API and get streaming result 93 | response = openai.ChatCompletion.create( 94 | model=self.model_engine, 95 | messages=request_messages, 96 | stream=True, 97 | temperature=0.3, 98 | max_tokens=self.max_tokens 99 | ) 100 | 101 | # Print the message in cli 102 | PrintUtil.gpt_print("", end='') 103 | 104 | # Iterate through the stream of events 105 | completion_text = '' 106 | for event in response: 107 | # Ignore the message which has no data 108 | if "delta" in event['choices'][0] and "content" in event['choices'][0]['delta']: 109 | event_text = event['choices'][0]['delta']['content'] 110 | completion_text += event_text 111 | # Ignore the first message which is line breaker 112 | if event_text == "\n\n": 113 | pass 114 | else: 115 | # Append the message and print in the same line 116 | print(event_text, end="") 117 | 118 | if update_history_message: 119 | # Append the response in history messages 120 | self.history_message_queue.append({"role": "assistant", "content": completion_text}) 121 | else: 122 | # Pop the user's request in history messages 123 | self.history_message_queue.pop() 124 | 125 | # Print the line breaker in cli 126 | print("") 127 | -------------------------------------------------------------------------------- /openmldb_chatgpt/help_util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from print_util import PrintUtil 16 | 17 | 18 | class HelpUtil: 19 | 20 | @staticmethod 21 | def print_help_message(): 22 | 23 | help_message = """ 24 | ####### # # # ###### ###### ##### ##### ###### ####### 25 | # # ##### ###### # # ## ## # # # # # # # # # ## ##### # # # # # 26 | # # # # # ## # # # # # # # # # # # # # # # # # # # # 27 | # # # # ##### # # # # # # # # # ###### # ###### # # # # #### ###### # 28 | # # ##### # # # # # # # # # # # # # # ###### # # # # # 29 | # # # # # ## # # # # # # # # # # # # # # # # # # 30 | ####### # ###### # # # # ####### ###### ###### ##### # # # # # ##### # # 31 | 32 | OpenMLDB ChatGPT 插件是一个集成了强大的 GPT 模型的 OpenMLDB 增强工具. 你可以在命令行中使用到以下功能: 33 | 34 | 1. 直接执行 OpenMLDB SQL 语句,例如 "SELECT 100"、"SHOW JOBS" 等,可立即返回计算结果。 35 | 2. 如果 SQL 执行成功,会自动解析 SQL 语义,例如输入"解释上面的SQL含义"、"分析上面的表数据"。 36 | 3. 如果 SQL 执行失败,会自动分析失败原因,例如输入 "解释SQL失败原因"、"改正上面的SQL语句"。 37 | 4. 如果不了解SQL语法或想了解OpenMLDB可直接提问,例如输入 "创建名为db1的数据库"、"查询系统有多少张表" 38 | 5. 所有自然语言提问都会保留上下文,可直接提问"上一个SQL是什么含义"、"请帮我优化上一个SQL语句"。 39 | 6. 如果模型返回的结果补全(因token数量限制),输入 "继续" 或者 "continuous" 继续查看模型返回的结果。 40 | 7. 使用 "help" 命令可打印帮助文档,使用 "q"、"quit"、"exit" 命令可退出命令行。 41 | """ 42 | 43 | PrintUtil.print_colorful("cyan", help_message) 44 | -------------------------------------------------------------------------------- /openmldb_chatgpt/history.txt: -------------------------------------------------------------------------------- 1 | 2 | # 2023-03-16 15:44:00.026686 3 | +cherry 4 | 5 | # 2023-03-16 15:45:29.446453 6 | +q 7 | 8 | # 2023-03-16 15:45:35.415170 9 | +SELECT 10 | 11 | # 2023-03-16 15:46:51.193367 12 | +Explain the following sql: "SELECT * FROM t1" 13 | 14 | # 2023-03-16 15:47:44.616850 15 | +q 16 | 17 | # 2023-03-16 15:47:48.573115 18 | +sdf 19 | 20 | # 2023-03-16 15:48:04.167470 21 | +what is your name 22 | 23 | # 2023-03-16 15:49:39.197514 24 | +what is your name hallo 25 | 26 | # 2023-03-16 15:50:01.139162 27 | +event 28 | 29 | # 2023-03-16 15:50:31.324904 30 | +how old are you 31 | 32 | # 2023-03-16 15:51:49.078040 33 | +q 34 | 35 | # 2023-03-16 15:52:01.632307 36 | +tell me how to create database in SQ 37 | 38 | # 2023-03-16 15:54:30.007291 39 | +q 40 | 41 | # 2023-03-16 15:54:34.987549 42 | +sdfasfasf 43 | 44 | # 2023-03-16 15:58:10.304430 45 | +q 46 | 47 | # 2023-03-16 15:59:54.076661 48 | +SELECT and fail 49 | 50 | # 2023-03-16 16:00:52.745640 51 | +q 52 | 53 | # 2023-03-16 16:01:04.405887 54 | +quit 55 | 56 | # 2023-03-16 16:01:22.654945 57 | +q 58 | 59 | # 2023-03-16 16:37:33.871097 60 | +how to make money with chatgpt 61 | 62 | # 2023-03-16 17:21:30.251229 63 | +q 64 | 65 | # 2023-03-16 17:21:50.670818 66 | +how to make money with chatgpt 67 | 68 | # 2023-03-16 17:21:56.299518 69 | +continues 70 | 71 | # 2023-03-16 17:22:05.286208 72 | +go on 73 | 74 | # 2023-03-16 17:22:31.651858 75 | +show me a SQL to create table 76 | 77 | # 2023-03-16 17:22:40.644334 78 | +go on 79 | 80 | # 2023-03-16 17:22:59.039236 81 | +q 82 | 83 | # 2023-03-16 17:23:33.053472 84 | +SELECT and fail 85 | 86 | # 2023-03-16 17:24:26.039607 87 | +tell me how to create database in SQ 88 | 89 | # 2023-03-16 17:24:33.708582 90 | +go on 91 | 92 | # 2023-03-16 17:24:36.794407 93 | +goon 94 | 95 | # 2023-03-16 17:24:56.713741 96 | +give me the above sql without comments 97 | 98 | # 2023-03-16 17:25:05.599354 99 | +go 100 | 101 | # 2023-03-16 17:25:10.428974 102 | +goon 103 | 104 | # 2023-03-16 17:25:19.376398 105 | +continues 106 | 107 | # 2023-03-16 17:25:44.816951 108 | +if a = 1, b=3, c=5, what above d 109 | 110 | # 2023-03-16 17:26:08.561774 111 | +if a is 1, b is3, c is 5, d is ? 112 | 113 | # 2023-03-16 17:26:21.797287 114 | +if a is 1, b is 2, c is 3, d is ? 115 | 116 | # 2023-03-16 17:26:26.459591 117 | +continues 118 | 119 | # 2023-03-16 17:26:56.498415 120 | +q 121 | 122 | # 2023-03-16 17:27:06.530028 123 | +if a is 1, b is 2, c is 3, d is ? 124 | 125 | # 2023-03-16 17:27:18.030903 126 | +how about e 127 | 128 | # 2023-03-16 17:27:31.496697 129 | +tell me a joke in Chinese 130 | 131 | # 2023-03-16 17:27:37.519410 132 | +continues 133 | 134 | # 2023-03-16 17:28:04.210293 135 | +stop 136 | 137 | # 2023-03-16 17:28:16.515528 138 | +what is your name 139 | 140 | # 2023-03-16 17:28:30.586359 141 | +translate hala into Japanese 142 | 143 | # 2023-03-16 17:28:38.737025 144 | +continues 145 | 146 | # 2023-03-16 17:28:48.746793 147 | +q 148 | 149 | # 2023-03-16 18:23:42.854038 150 | +next 151 | 152 | # 2023-03-16 18:23:47.654780 153 | +q 154 | 155 | # 2023-03-16 18:23:59.151375 156 | +ORDER BY 157 | 158 | # 2023-03-16 18:24:51.500072 159 | +q 160 | 161 | # 2023-03-16 18:25:07.538644 162 | +sdfa INSERT s 163 | 164 | # 2023-03-16 18:25:28.504170 165 | +q 166 | 167 | # 2023-03-16 18:27:49.899689 168 | +sdfaf sdfasfasf afdsa SELECT 169 | 170 | # 2023-03-16 18:28:34.107292 171 | +q 172 | 173 | # 2023-03-16 18:31:43.020791 174 | +hellow man 175 | 176 | # 2023-03-16 18:33:08.937395 177 | +q 178 | 179 | # 2023-03-16 18:33:30.554133 180 | +sdfa 181 | 182 | # 2023-03-16 18:34:24.516061 183 | +q 184 | 185 | # 2023-03-16 18:34:40.779626 186 | +hsll 187 | 188 | # 2023-03-16 18:35:42.021628 189 | +q 190 | 191 | # 2023-03-16 18:35:47.086406 192 | +whl 193 | 194 | # 2023-03-16 18:36:20.888877 195 | +hello 196 | 197 | # 2023-03-16 18:59:09.802046 198 | +q 199 | 200 | # 2023-03-16 19:05:33.387468 201 | +show jobs; 202 | 203 | # 2023-03-16 19:05:36.289436 204 | +show jobss; 205 | 206 | # 2023-03-16 19:07:05.986273 207 | +q 208 | 209 | # 2023-03-16 19:07:09.701504 210 | +ehll 211 | 212 | # 2023-03-16 19:07:36.201138 213 | +sd 214 | 215 | # 2023-03-16 19:08:02.229104 216 | +show josdf; 217 | 218 | # 2023-03-16 19:08:17.855191 219 | +sdf; 220 | 221 | # 2023-03-16 19:09:35.141714 222 | +q 223 | 224 | # 2023-03-16 19:09:38.557676 225 | +dsf 226 | 227 | # 2023-03-16 19:10:16.536329 228 | +show jobs; 229 | 230 | # 2023-03-16 19:10:23.196172 231 | +select 100; 232 | 233 | # 2023-03-16 19:12:41.650694 234 | +q 235 | 236 | # 2023-03-16 19:12:46.329396 237 | +select 100; 238 | 239 | # 2023-03-16 19:19:43.659904 240 | +SELECT 100; 241 | 242 | # 2023-03-16 19:19:47.120735 243 | +show jobs; 244 | 245 | # 2023-03-16 19:19:57.665008 246 | +create database db2; 247 | 248 | # 2023-03-16 19:22:47.484725 249 | +q 250 | 251 | # 2023-03-16 19:22:51.918437 252 | +show jobs; 253 | 254 | # 2023-03-16 19:23:02.311443 255 | +select 1; 256 | 257 | # 2023-03-16 19:26:56.129489 258 | +q 259 | 260 | # 2023-03-16 19:27:00.674228 261 | +show jobs; 262 | 263 | # 2023-03-16 19:27:18.692058 264 | +select 1; 265 | 266 | # 2023-03-16 19:27:32.472339 267 | +create database db3; 268 | 269 | # 2023-03-16 19:37:51.685229 270 | +select 1; 271 | 272 | # 2023-03-16 19:37:54.367313 273 | +show jobs; 274 | 275 | # 2023-03-16 19:38:49.962634 276 | +q 277 | 278 | # 2023-03-16 19:39:08.757258 279 | +show jobs; 280 | 281 | # 2023-03-16 19:39:38.169887 282 | +create database db3; 283 | 284 | # 2023-03-16 19:40:07.088964 285 | +create database db4 286 | 287 | # 2023-03-16 19:40:12.963893 288 | +show databases; 289 | 290 | # 2023-03-16 19:40:16.793879 291 | +show tables; 292 | 293 | # 2023-03-16 19:40:23.173967 294 | +use db1; 295 | 296 | # 2023-03-16 19:40:34.249807 297 | +use db10; 298 | 299 | # 2023-03-16 19:40:37.855890 300 | +show tables; 301 | 302 | # 2023-03-16 19:40:45.243052 303 | +create table t1 (col1 int); 304 | 305 | # 2023-03-16 19:40:49.598134 306 | +show tables; 307 | 308 | # 2023-03-16 19:41:13.387192 309 | +select * from t1; 310 | 311 | # 2023-03-16 19:42:35.569534 312 | +q 313 | 314 | # 2023-03-16 19:42:39.560088 315 | +show jobs; 316 | 317 | # 2023-03-16 19:42:44.047332 318 | +select 1; 319 | 320 | # 2023-03-16 19:42:49.133453 321 | +use db10; 322 | 323 | # 2023-03-16 19:42:52.054037 324 | +select * from t1; 325 | 326 | # 2023-03-16 19:43:25.233589 327 | +SET @@execute_mode="offline"; 328 | 329 | # 2023-03-16 19:43:31.454546 330 | +select 10; 331 | 332 | # 2023-03-16 19:43:34.227346 333 | +show jobs; 334 | 335 | # 2023-03-16 19:43:35.881244 336 | +show job 1; 337 | 338 | # 2023-03-16 19:43:45.431946 339 | +show joblog 1; 340 | 341 | # 2023-03-16 19:45:35.485389 342 | +q 343 | 344 | # 2023-03-16 19:45:38.456707 345 | +show jobs; 346 | 347 | # 2023-03-16 19:45:41.541463 348 | +show joblog 1; 349 | 350 | # 2023-03-16 19:46:02.201886 351 | +q 352 | 353 | # 2023-03-16 19:46:07.640104 354 | +show joblog 1; 355 | 356 | # 2023-03-16 19:46:24.000747 357 | +q 358 | 359 | # 2023-03-16 19:58:20.361633 360 | +help 361 | 362 | # 2023-03-16 19:58:32.697764 363 | +q 364 | 365 | # 2023-03-16 20:08:02.123744 366 | +help 367 | 368 | # 2023-03-16 20:08:13.482351 369 | +SELECT 100; 370 | 371 | # 2023-03-16 20:09:02.517243 372 | +q 373 | 374 | # 2023-03-16 20:14:28.159227 375 | +帮我生成一个创建数据库的SQL 376 | 377 | # 2023-03-16 20:16:28.976083 378 | +q 379 | 380 | # 2023-03-16 20:16:39.812100 381 | +帮我生成一个创建数据库的SQL 382 | 383 | # 2023-03-16 20:17:05.814438 384 | +帮我生成一个名为db1的数据库的SQL 385 | 386 | # 2023-03-16 20:17:12.517985 387 | +go on 388 | 389 | # 2023-03-16 20:17:41.225058 390 | +q 391 | 392 | # 2023-03-16 20:18:36.072003 393 | +生成创建db1数据库的SQL 394 | 395 | # 2023-03-16 20:19:06.226292 396 | +生成创建名为db1的数据库的SQL 397 | 398 | # 2023-03-16 20:19:28.456434 399 | +执行上面的SQL语句 400 | 401 | # 2023-03-16 20:20:53.872953 402 | +go on 403 | 404 | # 2023-03-16 20:21:40.332597 405 | +帮我查询系统有多少张表 406 | 407 | # 2023-03-16 20:22:28.833551 408 | +q 409 | 410 | # 2023-03-16 20:22:35.157137 411 | + 帮我查询系统有多少张表 412 | 413 | # 2023-03-16 20:22:57.729613 414 | +show jobs; 415 | 416 | # 2023-03-16 20:37:34.557413 417 | +help 418 | 419 | # 2023-03-16 20:38:31.136687 420 | +show jobs; 421 | 422 | # 2023-03-16 20:38:35.166370 423 | +select 1234; 424 | 425 | # 2023-03-16 20:38:44.593427 426 | +select * FROM db10.t1; 427 | 428 | # 2023-03-16 20:39:03.472099 429 | +生成一个SQL查询db10.t1的所有数据 430 | 431 | # 2023-03-16 20:43:34.129389 432 | +q 433 | 434 | # 2023-03-16 20:43:50.091760 435 | +你好SELECT * from 1 436 | 437 | # 2023-03-16 20:43:58.446001 438 | +selec 439 | 440 | # 2023-03-16 20:44:03.532033 441 | +SELECT 100 442 | 443 | # 2023-03-16 20:44:46.793146 444 | +show jobs; 445 | 446 | # 2023-03-16 20:44:49.147152 447 | +show job 1; 448 | 449 | # 2023-03-16 20:44:52.508933 450 | +show joblog 1; 451 | 452 | # 2023-03-16 20:44:57.762623 453 | +ls 454 | 455 | # 2023-03-16 20:45:09.847003 456 | +show tables; 457 | 458 | # 2023-03-17 01:50:35.298157 459 | +q 460 | 461 | # 2023-03-17 02:21:34.771965 462 | +select 103; 463 | 464 | # 2023-03-17 02:22:06.507953 465 | +q 466 | 467 | # 2023-03-17 02:22:23.557219 468 | +select col1 from db1.t1 469 | 470 | # 2023-03-17 02:23:21.868074 471 | +analyse the error message of '[1000] get tablet client failed--fail to explain select col1 from db1.t1--Fail to transform data provider op: table db1.t1 not exists in database [db1]' 472 | 473 | # 2023-03-17 02:24:12.919685 474 | +Analyse the error message of '[1000] get tablet client failed--fail to explain select col1 from db1.t1--Fail to transform data provider op: table db1.t1 not exists in database [db1]' and correct the SQL in 120 words 475 | 476 | # 2023-03-17 02:24:50.273662 477 | +Analyse the error message of '[1000] get tablet client failed--fail to explain select col1 from db1.t1--Fail to transform data provider op: table db1.t1 not exists in database [db1]' in 200 words 478 | 479 | # 2023-03-17 02:26:17.337382 480 | +create database db1; 481 | 482 | # 2023-03-17 02:26:31.311484 483 | +create table t1 (col1 int); 484 | 485 | # 2023-03-17 02:26:53.451112 486 | +use db1; 487 | 488 | # 2023-03-17 02:27:24.281676 489 | +USE db1; 490 | 491 | # 2023-03-17 02:28:35.098640 492 | +create table t1 (col1 int); 493 | 494 | # 2023-03-17 02:29:12.226169 495 | +use db1; 496 | 497 | # 2023-03-17 02:29:33.291149 498 | +q 499 | 500 | # 2023-03-17 02:29:38.761458 501 | +use db1; 502 | 503 | # 2023-03-17 02:29:46.295630 504 | +create table t1 (col1 int); 505 | 506 | # 2023-03-17 02:31:39.980211 507 | +q 508 | 509 | # 2023-03-17 02:31:46.431936 510 | +use db1; 511 | 512 | # 2023-03-17 02:31:50.971514 513 | +show tables; 514 | 515 | # 2023-03-17 02:32:26.275909 516 | +select * from db1.t1; 517 | 518 | # 2023-03-17 02:34:06.972390 519 | +q 520 | 521 | # 2023-03-17 02:34:57.070837 522 | +select * from db1.t1; 523 | 524 | # 2023-03-17 02:35:42.900630 525 | +update the above sql to select col1 526 | 527 | # 2023-03-17 02:37:02.974812 528 | +help 529 | 530 | # 2023-03-17 02:37:19.067838 531 | +select 100; 532 | 533 | # 2023-03-17 02:39:29.502285 534 | +markdown table example 535 | 536 | # 2023-03-17 02:43:16.055403 537 | +SELECT 100 + 234 538 | 539 | # 2023-03-17 02:44:21.662583 540 | +q 541 | 542 | # 2023-03-17 02:44:29.904706 543 | +select 100 + 23424; 544 | 545 | # 2023-03-17 02:45:35.453082 546 | +请解释上面的SQL含义 547 | 548 | # 2023-03-17 02:45:46.063100 549 | +请为上面的SQL添加注释 550 | 551 | # 2023-03-17 02:46:04.833170 552 | +select 123ad; 553 | 554 | # 2023-03-17 02:46:26.209681 555 | +请解释SQL执行失败原因 556 | 557 | # 2023-03-17 02:46:43.743917 558 | +请帮我改正上面失败的SQL语句 559 | 560 | # 2023-03-17 02:46:54.712199 561 | +select 123ad; 562 | 563 | # 2023-03-17 02:47:07.587987 564 | +帮我改正上面失败的SQL语句 565 | 566 | # 2023-03-17 02:48:00.073598 567 | +q 568 | 569 | # 2023-03-17 02:48:07.128182 570 | +select 123; 571 | 572 | # 2023-03-17 02:50:14.810962 573 | +nalyse the SQL 'SELECT 100' and optimize the SQL. Translate the replay in Chinese. 574 | 575 | # 2023-03-17 02:51:05.562658 576 | +Analyse the SQL 'SELECT 100' and optimize the SQL. Only output the translation of Chinese. 577 | 578 | # 2023-03-17 02:52:08.503198 579 | +分析SQL语句'SELECT 100'并尝试优化SQL语句 580 | 581 | # 2023-03-17 10:35:37.970475 582 | +select 234; 583 | 584 | # 2023-03-17 11:00:03.456096 585 | +select 123abc; 586 | 587 | # 2023-03-17 11:01:52.643223 588 | +select t1.c1, t2.c2 from t2; 589 | 590 | # 2023-03-17 12:03:08.285708 591 | +show databases; 592 | 593 | # 2023-03-17 12:05:42.494488 594 | +select 1234; 595 | 596 | # 2023-03-17 12:07:03.333390 597 | +q 598 | 599 | # 2023-03-17 12:07:09.493718 600 | +create database db1; 601 | 602 | # 2023-03-17 12:07:17.437732 603 | +use db1; 604 | 605 | # 2023-03-17 12:10:21.748653 606 | +create table t1 (col1 int); 607 | 608 | # 2023-03-17 12:10:34.829663 609 | +insert into db1.t1(values 23); 610 | 611 | # 2023-03-17 12:10:42.165917 612 | +insert into db1.t1 values (23); 613 | 614 | # 2023-03-17 12:10:48.709982 615 | +insert into db1.t1 values (11); 616 | 617 | # 2023-03-17 12:10:56.164048 618 | +select * from db1.t1; 619 | 620 | # 2023-03-17 12:27:11.192122 621 | +分析上面的表格数据 622 | 623 | # 2023-03-17 12:35:20.490146 624 | +q 625 | 626 | # 2023-03-17 12:35:26.637425 627 | +show databases; 628 | 629 | # 2023-03-17 12:36:00.180122 630 | +q 631 | 632 | # 2023-03-17 12:36:09.023729 633 | +create database db2; 634 | 635 | # 2023-03-17 12:36:23.384579 636 | +use db2; 637 | 638 | # 2023-03-17 12:36:42.558455 639 | +create table t2 (col1 int, col2 varchar(50)); 640 | 641 | # 2023-03-17 12:37:05.864118 642 | +insert into t2 (col1, col2) values (1, 'Hello'), (2, 'World'), (3, 'OpenMLDB'); 643 | 644 | # 2023-03-17 12:37:29.335542 645 | +create table t2 (col1 int, col2 varchar(50)); 646 | 647 | # 2023-03-17 12:37:50.603132 648 | +create database db2; 649 | 650 | # 2023-03-17 14:11:10.260828 651 | +q 652 | 653 | # 2023-03-17 14:24:22.284537 654 | +show jobs; 655 | 656 | # 2023-03-17 14:24:59.311436 657 | +select 1234; 658 | 659 | # 2023-03-17 14:25:47.065169 660 | +q 661 | 662 | # 2023-03-17 14:25:53.455582 663 | +select 1; 664 | 665 | # 2023-03-17 14:26:09.552451 666 | +show databases; 667 | 668 | # 2023-03-17 14:26:27.773275 669 | +q 670 | 671 | # 2023-03-17 14:31:47.917110 672 | +select 123abc; 673 | 674 | # 2023-03-17 14:32:00.766301 675 | +帮我改正SQL语句 676 | 677 | # 2023-03-17 14:32:08.302975 678 | +帮我改正上面的SQL语句 679 | 680 | # 2023-03-17 14:32:19.013844 681 | +select 123abc; 682 | 683 | # 2023-03-17 14:32:28.289094 684 | +帮我改正上面的SQL语句 685 | 686 | # 2023-03-17 14:33:07.983927 687 | +select 123abc; 688 | 689 | # 2023-03-17 14:33:12.691061 690 | +解释SQL失败原因 691 | 692 | # 2023-03-17 14:37:06.388340 693 | +q 694 | 695 | # 2023-03-17 14:37:19.967018 696 | +select sdafasf1; 697 | 698 | # 2023-03-17 14:37:43.714402 699 | +改正上面的SQL语句 700 | 701 | # 2023-03-17 14:38:02.926808 702 | +select * from db1.t22; 703 | 704 | # 2023-03-17 14:38:28.845865 705 | +分析上面的SQL失败原因 706 | 707 | # 2023-03-17 14:38:52.306547 708 | +改正上面的SQL语句 709 | 710 | # 2023-03-17 14:40:12.402298 711 | +如何创建一个数据库db1 712 | 713 | # 2023-03-17 14:40:29.200566 714 | +查询系统有多少张表 715 | 716 | # 2023-03-17 14:40:45.231580 717 | +查询数据库有多少张表 718 | 719 | # 2023-03-17 14:41:05.975408 720 | +查询所有数据表 721 | 722 | # 2023-03-17 14:41:45.785767 723 | +continuous 724 | 725 | # 2023-03-17 14:43:34.380442 726 | +q 727 | 728 | # 2023-03-17 14:51:40.160848 729 | +show databases; 730 | 731 | # 2023-03-17 15:04:05.719710 732 | +q 733 | 734 | # 2023-03-17 15:05:00.383552 735 | +show databases; 736 | 737 | # 2023-03-17 15:05:14.927849 738 | +select 1234ds; 739 | 740 | # 2023-03-17 15:05:39.098492 741 | +改正这个SQL语句 742 | 743 | # 2023-03-17 15:05:44.301010 744 | +改正上面的SQL语句 745 | 746 | # 2023-03-17 15:05:57.476680 747 | +select 1234ds; 748 | 749 | # 2023-03-17 15:06:12.501469 750 | +改正上面的SQL语句 751 | 752 | # 2023-03-17 15:06:23.108779 753 | +q 754 | 755 | # 2023-03-17 15:21:38.154394 756 | +help 757 | 758 | # 2023-03-17 15:21:53.531401 759 | +how to write a sql to query user data in db1 760 | 761 | # 2023-03-17 15:26:15.101059 762 | +show me how to CREATE DATABASE 763 | 764 | # 2023-03-17 15:26:30.527882 765 | +如何创建数据库 766 | 767 | # 2023-03-17 15:27:03.894349 768 | +create database db3; 769 | 770 | # 2023-03-17 15:27:57.227996 771 | +CREATE DATABASE db3; 772 | 773 | # 2023-03-17 15:28:06.464904 774 | +CREATE DATABASE db4; 775 | 776 | # 2023-03-17 15:28:27.457920 777 | +USE db4; 778 | 779 | # 2023-03-17 15:28:57.650933 780 | +q 781 | 782 | # 2023-03-17 15:38:38.081564 783 | +SELECT 100; 784 | 785 | # 2023-03-17 15:39:02.610100 786 | +q 787 | -------------------------------------------------------------------------------- /openmldb_chatgpt/openmldb_manager.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from openmldb.dbapi import connect 16 | from openmldb.dbapi import DatabaseError 17 | from tabulate import tabulate 18 | 19 | from print_util import PrintUtil 20 | from sql_util import SqlUtil 21 | 22 | 23 | class OpenmldbManager: 24 | 25 | def __init__(self, zk_cluster: str, zk_root_path: str): 26 | # Connect with zk 27 | self.connection = connect(zk=zk_cluster, zkPath=zk_root_path) 28 | self.cursor = self.connection.cursor() 29 | 30 | # Record the last SQL and error message, which may be used by GTP model to analyse 31 | self.last_sql = None 32 | self.last_sql_error_message = None 33 | 34 | def get_database_names(self): 35 | self.cursor.execute("SHOW DATABASES") 36 | rows = self.cursor.fetchall() 37 | database_names = [item[0] for item in rows] 38 | return database_names 39 | 40 | def get_all_table_info(self, database_names: list[str]) -> str: 41 | """ Example string: 42 | # db1.t1 (col1) 43 | # school.student (id, name, age) 44 | # school.teacher (id, name, subject) 45 | # fin_tect.bank (id, name, department_id) 46 | # fin_tect.user (id, name, address) 47 | # fin_tect.trade (id, employee_id, amount, date) 48 | """ 49 | table_name_columns_attributes = "" 50 | 51 | for database_name in database_names: 52 | self.cursor.execute(f"USE {database_name}") 53 | self.cursor.execute("SHOW TABLES") 54 | rows = self.cursor.fetchall() 55 | table_names = [item[0] for item in rows] 56 | for table_name in table_names: 57 | self.cursor.execute(f"SELECT * FROM {table_name} LIMIT 0") 58 | column_names = [description[0] for description in self.cursor.description] 59 | schema_string = ",".join(column_names) 60 | table_name_columns_attributes += f"# {database_name}.{table_name} ({schema_string})" 61 | 62 | return table_name_columns_attributes 63 | 64 | def run_openmldb_sql(self, sql) -> bool: 65 | """ 66 | Run the OpenMLDB SQL. 67 | 68 | :return true if it is successful and false if it fails 69 | """ 70 | 71 | self.last_sql = sql 72 | 73 | try: 74 | # Run OpenMLDB SQL 75 | self.cursor.execute(sql) 76 | 77 | if SqlUtil.is_dql(sql): 78 | PrintUtil.openmldb_print("Success to execute query SQL.") 79 | 80 | rows = self.cursor.fetchall() 81 | schema = [description[0] for description in self.cursor.description] 82 | 83 | if SqlUtil.is_show_joblog(sql): 84 | # Only show the job data 85 | print(rows[0][0]) 86 | else: 87 | # Show to data as table 88 | table_string = tabulate(rows, headers=schema, tablefmt='grid') 89 | print(table_string) 90 | 91 | else: 92 | # Print one line message for DML/DDL 93 | PrintUtil.openmldb_print(f"Success to execute SQL. Rows affected: {self.cursor.rowcount}") 94 | 95 | return True 96 | except DatabaseError as e: 97 | PrintUtil.openmldb_print("Fail to execute SQL and get error message: ") 98 | PrintUtil.openmldb_print(e.message) 99 | self.last_sql_error_message = e.message 100 | return False 101 | 102 | def close(self): 103 | self.cursor.close() 104 | self.connection.close() 105 | -------------------------------------------------------------------------------- /openmldb_chatgpt/print_util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | class PrintUtil: 16 | 17 | @staticmethod 18 | def print_colorful(color, text, end='\n'): 19 | color_codes = { 20 | 'black': 30, 21 | 'red': 31, 22 | 'green': 32, 23 | 'yellow': 33, 24 | 'blue': 34, 25 | 'magenta': 35, 26 | 'cyan': 36, 27 | 'white': 37, 28 | } 29 | color_sequence = f"\033[{color_codes[color]}m" 30 | reset_sequence = "\033[0m" 31 | print(f"{color_sequence}{text}{reset_sequence}", end=end) 32 | 33 | @staticmethod 34 | def user_print(text, end='\n'): 35 | PrintUtil.print_colorful("blue", "USER > " + text, end) 36 | 37 | @staticmethod 38 | def gpt_print(text, end='\n'): 39 | PrintUtil.print_colorful("green", "GPT > " + text, end) 40 | 41 | @staticmethod 42 | def openmldb_print(text, end='\n'): 43 | PrintUtil.print_colorful("yellow", "OpenMLDB > " + text, end) 44 | -------------------------------------------------------------------------------- /openmldb_chatgpt/sql_util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import re 16 | 17 | 18 | class SqlUtil: 19 | 20 | @staticmethod 21 | def autocomplete_keywords(): 22 | # words = ['SELECT', 'INSERT', 'LOAD', 'CREATE DATABASE', 'CREATE TABLE', 'FROM'] 23 | # sql_keyword_string = "SELECT, FROM, WHERE, AND, OR, NOT, ORDER BY, GROUP BY, HAVING, DISTINCT, COUNT, SUM, AVG, MAX, MIN, INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN, CROSS JOIN, ON, AS, IN, BETWEEN, LIKE, LIMIT, OFFSET, UNION, UNION ALL, INSERT INTO, VALUES, UPDATE, SET, DELETE, CREATE DATABASE, DROP DATABASE, CREATE TABLE, DROP TABLE, ALTER TABLE, ADD, DROP, MODIFY, CONSTRAINT, PRIMARY KEY, FOREIGN KEY, CHECK, UNIQUE, DEFAULT, NULL, NOT NULL, INDEX, AUTO_INCREMENT, COMMIT, ROLLBACK, TRANSACTION, GRANT, REVOKE, TRUNCATE, SHOW, JOB, JOBS, LOG, LAST JOIN, INTO, OUTFILE, @@execute_mode='online', @@execute_mode='offline'" 24 | # work 25 | 26 | sql_keyword_string = "SELECT, FROM, USE, WHERE, AND, OR, NOT, ORDER BY, GROUP BY, HAVING, COUNT, SUM, AVG, MAX, MIN, ON, AS, IN, BETWEEN, LIKE, LIMIT, UNION, UNION ALL, INSERT INTO, VALUES, UPDATE, SET, DELETE, CREATE DATABASE, DROP DATABASE, CREATE TABLE, DROP TABLE, ADD, DROP, DEFAULT, NULL, NOT NULL, SHOW, JOB, JOBS, LOG, LAST JOIN, INTO, OUTFILE" 27 | # sql_keywords = map(str.strip, sql_keyword_string.split(",")) 28 | # TODO: too much and not work 29 | sql_keywords = ['SELECT', 'INSERT', 'LOAD', 'CREATE DATABASE', 'CREATE TABLE', 'FROM'] 30 | return sql_keywords 31 | 32 | def has_non_english_letters(text): 33 | pattern = re.compile(r'[^\x00-\x7F]+') 34 | return bool(pattern.search(text)) 35 | 36 | @staticmethod 37 | def is_possible_sql(text: str) -> bool: 38 | # Check if the text contains non English 39 | if SqlUtil.has_non_english_letters(text): 40 | return False 41 | 42 | text = re.sub(r'--.*$', '', text, flags=re.MULTILINE) 43 | text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL) 44 | text = text.strip() 45 | 46 | # Check for common SQL keywords 47 | keywords = ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'CREATE', 'ALTER', 'DROP', 'TRUNCATE', 'GRANT', 'REVOKE', 48 | 'SHOW', 'LOAD', 'SET', 'USE', 'GET'] 49 | return any([text.upper().startswith(keyword) for keyword in keywords]) 50 | 51 | @staticmethod 52 | def is_dql(sql: str) -> bool: 53 | sql_keyword = sql.split()[0].upper() 54 | if sql_keyword in ["SELECT", "SHOW"]: 55 | return True 56 | else: 57 | return False 58 | 59 | @staticmethod 60 | def is_show_joblog(sql: str) -> bool: 61 | if sql.lower().startswith("show joblog"): 62 | return True 63 | else: 64 | return False 65 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | configparser 16 | prompt_toolkit 17 | tabulate 18 | openai 19 | openmldb 20 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Update the code and upload the package to pypi 16 | # 1. python ./setup.py bdist_wheel --universal 17 | # 2. twine upload dist/openmldb_chatgpt-x.x.x-py2.py3-none-any.whl 18 | 19 | from setuptools import setup, find_packages 20 | 21 | setup( 22 | name="openmldb-chatgpt", 23 | version="0.1.1", 24 | author="tobe", 25 | author_email="tobeg3oogle@gmail.com", 26 | url="https://github.com/tobegit3hub/openmldb-chatgpt-plugin", 27 | description="The ChatGPT plugin to enhance OpenMLDB.", 28 | packages=find_packages(), 29 | install_requires=[ 30 | 'configparser', 'prompt_toolkit', 'tabulate', 'openai', 'openmldb' 31 | ], 32 | include_package_data=True, 33 | zip_safe=False, 34 | entry_points={ 35 | "console_scripts": [ 36 | "openmldb-chatgpt=openmldb_chatgpt.cli:main" 37 | ], 38 | }) 39 | --------------------------------------------------------------------------------