├── .github └── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── .gitignore ├── README.md ├── db_query ├── .difyignore ├── .env.example ├── .gitignore ├── GUIDE.md ├── PRIVACY.md ├── README.md ├── _assets │ ├── db_query.png │ ├── db_query_chatflow.png │ ├── db_query_sql_query.png │ ├── icon.svg │ ├── llm_riddles1.png │ ├── llm_riddles2.png │ └── llm_riddles3.png ├── main.py ├── manifest.yaml ├── provider │ ├── db_query.py │ └── db_query.yaml ├── requirements.txt └── tools │ ├── db_util.py │ ├── sql_query.py │ └── sql_query.yaml ├── db_query_pre_auth ├── .difyignore ├── .env.example ├── .gitignore ├── GUIDE.md ├── PRIVACY.md ├── README.md ├── _assets │ ├── db_query_pre_auth.png │ ├── db_query_pre_auth_setup_auth.png │ ├── icon.svg │ ├── llm_riddles1.png │ ├── llm_riddles2.png │ └── llm_riddles3.png ├── main.py ├── manifest.yaml ├── provider │ ├── db_query.py │ └── db_query.yaml ├── requirements.txt └── tools │ ├── db_util.py │ ├── sql_query.py │ └── sql_query.yaml ├── examples ├── 完蛋!我被LLM包围了!(Dify1.0战绩排行+留言版).yml └── 完蛋!我被LLM包围了!(Dify1.0战绩排行版).yml └── images ├── db_query.png ├── db_query_pre_auth.png ├── dify_plugin_daemon_update.png ├── install_plugin_via_github.png └── install_plugin_via_local.png /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: "🕷️ Bug report Bug报告" 2 | description: "Report errors or unexpected behavior. 创建一个 Bug 报告以帮助我们改进。" 3 | labels: 4 | - bug 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: "Please confirm before submission 在提交之前,请确认" 9 | options: 10 | - label: | 11 | I have searched for existing issues [search for existing issues](https://github.com/junjiem/dify-plugin-tools-dbquery/issues), including closed ones. 12 | 我已经搜索了现有问题[搜索现有问题](https://github.com/junjiem/dify-plugin-tools-dbquery/issues),包括已关闭的问题。" 13 | required: true 14 | - type: input 15 | attributes: 16 | label: "Dify version Dify版本" 17 | validations: 18 | required: true 19 | - type: dropdown 20 | attributes: 21 | label: db_query or db_query_pre_auth 22 | description: Which plugin? 哪个插件? 23 | multiple: true 24 | options: 25 | - Database Query 数据库查询 26 | - Database Query (Pre-authorization) 数据库查询(预授权) 27 | validations: 28 | required: true 29 | - type: input 30 | attributes: 31 | label: "Plugin version 插件版本" 32 | validations: 33 | required: true 34 | - type: input 35 | attributes: 36 | label: database and version 数据库及版本 37 | validations: 38 | required: true 39 | - type: textarea 40 | attributes: 41 | label: "Problem description 问题描述" 42 | description: "Please describe the problem you have encountered clearly and concisely. 请清晰简洁地描述你遇到的问题。" 43 | validations: 44 | required: true 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: "\U0001F4E7 Discussions 讨论" 4 | url: https://github.com/junjiem/dify-plugin-tools-dbquery/discussions 5 | about: General discussions and request help. 一般性讨论和请求帮助。 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: "⭐ Feature or enhancement request 特性或增强请求" 2 | description: Propose something new. 提出一些新的建议。 3 | labels: 4 | - enhancement 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: "Please confirm before submission 在提交之前,请确认" 9 | options: 10 | - label: | 11 | I have searched for existing issues [search for existing issues](https://github.com/junjiem/dify-plugin-tools-dbquery/issues), including closed ones. 12 | 我已经搜索了现有问题[搜索现有问题](https://github.com/junjiem/dify-plugin-tools-dbquery/issues),包括已关闭的问题。" 13 | required: true 14 | - type: textarea 15 | attributes: 16 | label: Is this request related to a challenge you're experiencing? Tell me about your story. 这个请求与你正在经历的挑战有关吗?给我讲讲你的故事。 17 | placeholder: | 18 | Please describe the specific scenario or problem you're facing as clearly as possible. For instance "I was trying to use [feature] for [specific task], and [what happened]... It was frustrating because...." 19 | 请尽可能清楚地描述你所面临的具体场景或问题。例如:“我试图将[功能]用于[特定任务],但[发生了什么]……这很令人沮丧,因为....” 20 | validations: 21 | required: true 22 | - type: checkboxes 23 | attributes: 24 | label: Can you help us with this feature? 你能帮我们实现这个功能吗? 25 | description: Let us know! This is not a commitment, but a starting point for collaboration. 让我们知道!这不是承诺,而是合作的起点。 26 | options: 27 | - label: I am interested in contributing to this feature. 我有兴趣为这个特性做贡献。 28 | required: false 29 | - type: markdown 30 | attributes: 31 | value: Please limit one request per issue. 请限制每个问题一个请求。 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/*.log 3 | *.iml 4 | target/ 5 | 6 | # Editor directories and files 7 | .idea 8 | .vscode 9 | */.env 10 | *.suo 11 | *.ntvs* 12 | *.njsproj 13 | *.sln 14 | *.local 15 | 16 | .gradle/ 17 | tmp/ 18 | build/ 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Dify 1.0 Plugin Database Query Tools 2 | 3 | 4 | --- 5 | 6 | 7 | ### Demonstration 8 | 9 | Currently supported database types: mysql, oracle, [oracle11g](./db_query/README.md#2-how-to-connect-to-oracle-11g--如何连接oracle-11g), postgresql, or mssql. 10 | 11 | 目前支持的数据库类型:mysql、oracle、[oracle11g](./db_query/README.md#2-how-to-connect-to-oracle-11g--如何连接oracle-11g)、postgresql、mssql。 12 | 13 |  14 | 15 |  16 | 17 |  18 | 19 | 20 | --- 21 | 22 | 23 | 24 | ### Tools 25 | 26 | #### Database Query Utils 数据库查询工具 27 | 28 |  29 | 30 | 31 | 32 | #### Database Query Utils (Pre-authorization) 数据库查询工具(预授权) 33 | 34 |  35 | 36 | 37 | --- 38 | 39 | 40 | 41 | ### Installing Plugins via GitHub 通过 GitHub 安装插件 42 | 43 | Can install the plugin using the GitHub repository address. Visit the Dify platform's plugin management page, choose to install via GitHub, enter the repository address, select version number and package file to complete installation. 44 | 45 | 可以通过 GitHub 仓库地址安装该插件。访问 Dify 平台的插件管理页,选择通过 GitHub 安装插件,输入仓库地址后,选择版本号和包文件完成安装。 46 | 47 |  48 | 49 | 50 | 51 | --- 52 | 53 | 54 | ### Installing Plugins via Local 通过本地安装插件 55 | 56 | If the plugin cannot be installed via GitHub due to network issues, you can [manually download plugin package](https://github.com/junjiem/dify-plugin-tools-dbquery/releases/latest). 57 | Visit the Dify platform's plugin management page, choose Local Package File to complete installation. 58 | 59 | 如果由于网络问题导致无法通过 GitHub 安装插件,可以 [手动下载插件包](https://github.com/junjiem/dify-plugin-tools-dbquery/releases/latest),访问 Dify 平台的插件管理页,选择通过本地插件完成安装。 60 | 61 |  62 | 63 | 64 | 65 | --- 66 | 67 | 68 | 69 | ### FAQ 70 | 71 | #### How to Handle Errors When Installing Plugins? 安装插件时遇到异常应如何处理? 72 | 73 | **Issue**: If you encounter the error message: plugin verification has been enabled, and the plugin you want to install has a bad signature, how to handle the issue? 74 | 75 | **Solution**: Add the following line to the end of your .env configuration file: FORCE_VERIFYING_SIGNATURE=false 76 | Once this field is added, the Dify platform will allow the installation of all plugins that are not listed (and thus not verified) in the Dify Marketplace. 77 | 78 | **问题描述**:安装插件时遇到异常信息:plugin verification has been enabled, and the plugin you want to install has a bad signature,应该如何处理? 79 | 80 | **解决办法**:在 .env 配置文件的末尾添加 FORCE_VERIFYING_SIGNATURE=false 字段即可解决该问题。 81 | 添加该字段后,Dify 平台将允许安装所有未在 Dify Marketplace 上架(审核)的插件,可能存在安全隐患。 82 | 83 | 84 | 85 | --- 86 | 87 | 88 | 89 | ### Examples 示例 90 | 91 | - [完蛋!我被LLM包围了!(Dify1.0战绩排行版)](./examples/完蛋!我被LLM包围了!(Dify1.0战绩排行版).yml) 92 | 93 | - [完蛋!我被LLM包围了!(Dify1.0战绩排行+留言版)](./examples/完蛋!我被LLM包围了!(Dify1.0战绩排行+留言版).yml) 94 | 95 | 96 |  97 | 98 |  99 | 100 |  101 | 102 | 103 | 104 | --- 105 | 106 | 107 | 108 | ### Dify Plugin Downloading and Repackaging Scripting Tool Dify插件下载并重打包脚本工具 109 | 110 | Scripting tool for downloading Dify plugin package from Dify Marketplace and Github and repackaging [true] offline package (contains dependencies, no need to be connected to the Internet). 111 | 112 | 从Dify市场和Github下载Dify插件包并重新打【真】离线包(包含依赖,不需要再联网)的脚本工具。 113 | 114 | Github Repo: https://github.com/junjiem/dify-plugin-repackaging 115 | 116 | 117 | 118 | --- 119 | 120 | 121 | 122 | ### Star history 123 | 124 | [](https://star-history.com/#junjiem/dify-plugin-tools-dbquery&Date) 125 | 126 | 127 | -------------------------------------------------------------------------------- /db_query/.difyignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Distribution / packaging 7 | .Python 8 | build/ 9 | develop-eggs/ 10 | dist/ 11 | downloads/ 12 | eggs/ 13 | .eggs/ 14 | lib/ 15 | lib64/ 16 | parts/ 17 | sdist/ 18 | var/ 19 | wheels/ 20 | share/python-wheels/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | MANIFEST 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .nox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *.cover 46 | *.py,cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | cover/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | db.sqlite3-journal 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | .pybuilder/ 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # IPython 79 | profile_default/ 80 | ipython_config.py 81 | 82 | # pyenv 83 | # For a library or package, you might want to ignore these files since the code is 84 | # intended to run in multiple environments; otherwise, check them in: 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | Pipfile.lock 93 | 94 | # UV 95 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 96 | # This is especially recommended for binary packages to ensure reproducibility, and is more 97 | # commonly ignored for libraries. 98 | uv.lock 99 | 100 | # poetry 101 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 102 | # This is especially recommended for binary packages to ensure reproducibility, and is more 103 | # commonly ignored for libraries. 104 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 105 | poetry.lock 106 | 107 | # pdm 108 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 109 | #pdm.lock 110 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 111 | # in version control. 112 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 113 | .pdm.toml 114 | .pdm-python 115 | .pdm-build/ 116 | 117 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 118 | __pypackages__/ 119 | 120 | # Celery stuff 121 | celerybeat-schedule 122 | celerybeat.pid 123 | 124 | # SageMath parsed files 125 | *.sage.py 126 | 127 | # Environments 128 | .env 129 | .venv 130 | env/ 131 | venv/ 132 | ENV/ 133 | env.bak/ 134 | venv.bak/ 135 | 136 | # Spyder project settings 137 | .spyderproject 138 | .spyproject 139 | 140 | # Rope project settings 141 | .ropeproject 142 | 143 | # mkdocs documentation 144 | /site 145 | 146 | # mypy 147 | .mypy_cache/ 148 | .dmypy.json 149 | dmypy.json 150 | 151 | # Pyre type checker 152 | .pyre/ 153 | 154 | # pytype static type analyzer 155 | .pytype/ 156 | 157 | # Cython debug symbols 158 | cython_debug/ 159 | 160 | # PyCharm 161 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 162 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 163 | # and can be added to the global gitignore or merged into this file. For a more nuclear 164 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 165 | .idea/ 166 | 167 | # Vscode 168 | .vscode/ 169 | 170 | # Git 171 | .git/ 172 | .gitignore 173 | 174 | # Mac 175 | .DS_Store 176 | 177 | # Windows 178 | Thumbs.db 179 | -------------------------------------------------------------------------------- /db_query/.env.example: -------------------------------------------------------------------------------- 1 | INSTALL_METHOD=remote 2 | REMOTE_INSTALL_HOST=debug-plugin.dify.dev 3 | REMOTE_INSTALL_PORT=5003 4 | REMOTE_INSTALL_KEY=********-****-****-****-************ 5 | -------------------------------------------------------------------------------- /db_query/.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 | # UV 98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | #uv.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 116 | .pdm.toml 117 | .pdm-python 118 | .pdm-build/ 119 | 120 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 121 | __pypackages__/ 122 | 123 | # Celery stuff 124 | celerybeat-schedule 125 | celerybeat.pid 126 | 127 | # SageMath parsed files 128 | *.sage.py 129 | 130 | # Environments 131 | .env 132 | .venv 133 | env/ 134 | venv/ 135 | ENV/ 136 | env.bak/ 137 | venv.bak/ 138 | 139 | # Spyder project settings 140 | .spyderproject 141 | .spyproject 142 | 143 | # Rope project settings 144 | .ropeproject 145 | 146 | # mkdocs documentation 147 | /site 148 | 149 | # mypy 150 | .mypy_cache/ 151 | .dmypy.json 152 | dmypy.json 153 | 154 | # Pyre type checker 155 | .pyre/ 156 | 157 | # pytype static type analyzer 158 | .pytype/ 159 | 160 | # Cython debug symbols 161 | cython_debug/ 162 | 163 | # PyCharm 164 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 165 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 166 | # and can be added to the global gitignore or merged into this file. For a more nuclear 167 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 168 | .idea/ 169 | 170 | # Vscode 171 | .vscode/ 172 | -------------------------------------------------------------------------------- /db_query/GUIDE.md: -------------------------------------------------------------------------------- 1 | ## User Guide of how to develop a Dify Plugin 2 | 3 | Hi there, looks like you have already created a Plugin, now let's get you started with the development! 4 | 5 | ### Choose a Plugin type you want to develop 6 | 7 | Before start, you need some basic knowledge about the Plugin types, Plugin supports to extend the following abilities in Dify: 8 | - **Tool**: Tool Providers like Google Search, Stable Diffusion, etc. it can be used to perform a specific task. 9 | - **Model**: Model Providers like OpenAI, Anthropic, etc. you can use their models to enhance the AI capabilities. 10 | - **Endpoint**: Like Service API in Dify and Ingress in Kubernetes, you can extend a http service as an endpoint and control its logics using your own code. 11 | 12 | Based on the ability you want to extend, we have divided the Plugin into three types: **Tool**, **Model**, and **Extension**. 13 | 14 | - **Tool**: It's a tool provider, but not only limited to tools, you can implement an endpoint there, for example, you need both `Sending Message` and `Receiving Message` if you are building a Discord Bot, **Tool** and **Endpoint** are both required. 15 | - **Model**: Just a model provider, extending others is not allowed. 16 | - **Extension**: Other times, you may only need a simple http service to extend the functionalities, **Extension** is the right choice for you. 17 | 18 | I believe you have chosen the right type for your Plugin while creating it, if not, you can change it later by modifying the `manifest.yaml` file. 19 | 20 | ### Manifest 21 | 22 | Now you can edit the `manifest.yaml` file to describe your Plugin, here is the basic structure of it: 23 | 24 | - version(version, required):Plugin's version 25 | - type(type, required):Plugin's type, currently only supports `plugin`, future support `bundle` 26 | - author(string, required):Author, it's the organization name in Marketplace and should also equals to the owner of the repository 27 | - label(label, required):Multi-language name 28 | - created_at(RFC3339, required):Creation time, Marketplace requires that the creation time must be less than the current time 29 | - icon(asset, required):Icon path 30 | - resource (object):Resources to be applied 31 | - memory (int64):Maximum memory usage, mainly related to resource application on SaaS for serverless, unit bytes 32 | - permission(object):Permission application 33 | - tool(object):Reverse call tool permission 34 | - enabled (bool) 35 | - model(object):Reverse call model permission 36 | - enabled(bool) 37 | - llm(bool) 38 | - text_embedding(bool) 39 | - rerank(bool) 40 | - tts(bool) 41 | - speech2text(bool) 42 | - moderation(bool) 43 | - node(object):Reverse call node permission 44 | - enabled(bool) 45 | - endpoint(object):Allow to register endpoint permission 46 | - enabled(bool) 47 | - app(object):Reverse call app permission 48 | - enabled(bool) 49 | - storage(object):Apply for persistent storage permission 50 | - enabled(bool) 51 | - size(int64):Maximum allowed persistent memory, unit bytes 52 | - plugins(object, required):Plugin extension specific ability yaml file list, absolute path in the plugin package, if you need to extend the model, you need to define a file like openai.yaml, and fill in the path here, and the file on the path must exist, otherwise the packaging will fail. 53 | - Format 54 | - tools(list[string]): Extended tool suppliers, as for the detailed format, please refer to [Tool Guide](https://docs.dify.ai/docs/plugins/standard/tool_provider) 55 | - models(list[string]):Extended model suppliers, as for the detailed format, please refer to [Model Guide](https://docs.dify.ai/docs/plugins/standard/model_provider) 56 | - endpoints(list[string]):Extended Endpoints suppliers, as for the detailed format, please refer to [Endpoint Guide](https://docs.dify.ai/docs/plugins/standard/endpoint_group) 57 | - Restrictions 58 | - Not allowed to extend both tools and models 59 | - Not allowed to have no extension 60 | - Not allowed to extend both models and endpoints 61 | - Currently only supports up to one supplier of each type of extension 62 | - meta(object) 63 | - version(version, required):manifest format version, initial version 0.0.1 64 | - arch(list[string], required):Supported architectures, currently only supports amd64 arm64 65 | - runner(object, required):Runtime configuration 66 | - language(string):Currently only supports python 67 | - version(string):Language version, currently only supports 3.12 68 | - entrypoint(string):Program entry, in python it should be main 69 | 70 | ### Install Dependencies 71 | 72 | - First of all, you need a Python 3.11+ environment, as our SDK requires that. 73 | - Then, install the dependencies: 74 | ```bash 75 | pip install -r requirements.txt 76 | ``` 77 | - If you want to add more dependencies, you can add them to the `requirements.txt` file, once you have set the runner to python in the `manifest.yaml` file, `requirements.txt` will be automatically generated and used for packaging and deployment. 78 | 79 | ### Implement the Plugin 80 | 81 | Now you can start to implement your Plugin, by following these examples, you can quickly understand how to implement your own Plugin: 82 | 83 | - [OpenAI](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/openai): best practice for model provider 84 | - [Google Search](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/google): a simple example for tool provider 85 | - [Neko](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko): a funny example for endpoint group 86 | 87 | ### Test and Debug the Plugin 88 | 89 | You may already noticed that a `.env.example` file in the root directory of your Plugin, just copy it to `.env` and fill in the corresponding values, there are some environment variables you need to set if you want to debug your Plugin locally. 90 | 91 | - `INSTALL_METHOD`: Set this to `remote`, your plugin will connect to a Dify instance through the network. 92 | - `REMOTE_INSTALL_HOST`: The host of your Dify instance, you can use our SaaS instance `https://debug.dify.ai`, or self-hosted Dify instance. 93 | - `REMOTE_INSTALL_PORT`: The port of your Dify instance, default is 5003 94 | - `REMOTE_INSTALL_KEY`: You should get your debugging key from the Dify instance you used, at the right top of the plugin management page, you can see a button with a `debug` icon, click it and you will get the key. 95 | 96 | Run the following command to start your Plugin: 97 | 98 | ```bash 99 | python -m main 100 | ``` 101 | 102 | Refresh the page of your Dify instance, you should be able to see your Plugin in the list now, but it will be marked as `debugging`, you can use it normally, but not recommended for production. 103 | 104 | ### Package the Plugin 105 | 106 | After all, just package your Plugin by running the following command: 107 | 108 | ```bash 109 | dify-plugin plugin package ./ROOT_DIRECTORY_OF_YOUR_PLUGIN 110 | ``` 111 | 112 | you will get a `plugin.difypkg` file, that's all, you can submit it to the Marketplace now, look forward to your Plugin being listed! 113 | 114 | 115 | ## User Privacy Policy 116 | 117 | Please fill in the privacy policy of the plugin if you want to make it published on the Marketplace, refer to [PRIVACY.md](PRIVACY.md) for more details. -------------------------------------------------------------------------------- /db_query/PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | This tool is designed with privacy in mind and does not collect any user data. We are committed to maintaining your privacy and ensuring your data remains secure. 4 | 5 | ## Data Collection 6 | 7 | - **No Personal Information**: We do not collect, store, or process any personal information. 8 | - **No Usage Data**: We do not track or monitor how you use the tool. 9 | - **No Analytics**: We do not implement any analytics or tracking mechanisms. 10 | 11 | ## Third-Party Services 12 | 13 | This tool does not integrate with or utilize any third-party services that might collect user data. 14 | 15 | ## Changes to Privacy Policy 16 | 17 | If there are any changes to our privacy practices, we will update this document accordingly. -------------------------------------------------------------------------------- /db_query/README.md: -------------------------------------------------------------------------------- 1 | ## Dify 1.0 Plugin Database Query Tools 2 | 3 | 4 | **Author:** [Junjie.M](https://github.com/junjiem) 5 | **Type:** tool 6 | **Github Repo:** [https://github.com/junjiem/dify-plugin-tools-dbquery](https://github.com/junjiem/dify-plugin-tools-dbquery) 7 | **Github Issues:** [issues](https://github.com/junjiem/dify-plugin-tools-dbquery/issues) 8 | 9 | 10 | --- 11 | 12 | 13 | ### Demonstration 14 | 15 | Database Query Tools 16 | 17 | 数据库查询工具 18 | 19 | Currently supported database types: mysql, oracle, [oracle11g](#2-how-to-connect-to-oracle-11g--如何连接oracle-11g), postgresql, or mssql. 20 | 21 | 目前支持的数据库类型:mysql、oracle、[oracle11g](#2-how-to-connect-to-oracle-11g--如何连接oracle-11g)、postgresql、mssql。 22 | 23 |  24 | 25 |  26 | 27 |  28 | 29 | 30 | 31 | --- 32 | 33 | 34 | 35 | ### Examples 示例 36 | 37 | - [完蛋!我被LLM包围了!(Dify1.0战绩排行版)](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/examples/完蛋!我被LLM包围了!(Dify1.0战绩排行版).yml) 38 | 39 | - [完蛋!我被LLM包围了!(Dify1.0战绩排行+留言版)](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/examples/完蛋!我被LLM包围了!(Dify1.0战绩排行+留言版).yml) 40 | 41 | 42 |  43 | 44 |  45 | 46 |  47 | 48 | 49 | 50 | --- 51 | 52 | 53 | 54 | ### FAQ 55 | 56 | #### 1. How to Handle Errors When Installing Plugins? 安装插件时遇到异常应如何处理? 57 | 58 | **Issue**: If you encounter the error message: plugin verification has been enabled, and the plugin you want to install has a bad signature, how to handle the issue? 59 | 60 | **Solution**: Add the following line to the end of your .env configuration file: FORCE_VERIFYING_SIGNATURE=false 61 | Once this field is added, the Dify platform will allow the installation of all plugins that are not listed (and thus not verified) in the Dify Marketplace. 62 | 63 | **问题描述**:安装插件时遇到异常信息:plugin verification has been enabled, and the plugin you want to install has a bad signature,应该如何处理? 64 | 65 | **解决办法**:在 .env 配置文件的末尾添加 FORCE_VERIFYING_SIGNATURE=false 字段即可解决该问题。 66 | 添加该字段后,Dify 平台将允许安装所有未在 Dify Marketplace 上架(审核)的插件,可能存在安全隐患。 67 | 68 | 69 | #### 2. How to connect to oracle 11g 如何连接Oracle 11g 70 | 71 | 2.1、下载 oracle11g 的 client,这里下的是 11.2.0.4.0 版本 72 | 73 | https://www.oracle.com/database/technologies/instant-client/downloads.html 74 | 75 | 比如:instantclient-basic-linux.x64-11.2.0.4.0.zip 76 | 77 | 78 | 2.2、上传 oracle 的 client 到宿主机的 dify 的挂载目录 79 | 80 | 将 instantclient-basic-linux.x64-11.2.0.4.0.zip 解压后的 instantclient_11_2 目录放到 docker/volumes 下面 81 | > 注:需要将 `instantclient_11_2` 中`libclntsh.so.11.1` 改成 `libclntsh.so`、 `libocci.so.11.1` 改成 `libocci.so` 82 | 83 | 2.3、在 `docker/docker-compose.yml` 中进行配置 84 | ``` 85 | # 在 plugin_daemon 下,添加一个变量 86 | environment: 87 | ...... 88 | LD_LIBRARY_PATH: "/root/instantclient_11_2:$LD_LIBRARY_PATH" 89 | ``` 90 | 91 | Red Hat 系(如 CentOS、RHEL)64 位: 92 | ``` 93 | # 在 plugin_daemon 下,添加三个挂载 94 | volumes: 95 | ...... 96 | - ./volumes/instantclient_11_2:/root/instantclient_11_2 97 | - /usr/lib64/libaio.so.1.0.1:/usr/lib/x86_64-linux-gnu/libaio.so.1.0.1 98 | - /usr/lib64/libaio.so.1:/usr/lib/x86_64-linux-gnu/libaio.so.1 99 | ``` 100 | 101 | Debian 系(如 Ubuntu)64 位: 102 | ``` 103 | # 在 plugin_daemon 下,添加三个挂载 104 | volumes: 105 | ...... 106 | - ./volumes/instantclient_11_2:/root/instantclient_11_2 107 | - /usr/lib/x86_64-linux-gnu/libaio.so.1.0.1:/usr/lib/x86_64-linux-gnu/libaio.so.1.0.1 108 | - /usr/lib/x86_64-linux-gnu/libaio.so.1:/usr/lib/x86_64-linux-gnu/libaio.so.1 109 | ``` 110 | 111 | 2.4、重启 plugin_daemon 112 | ```shell 113 | docker stop docker-plugin_daemon-1 114 | docker compose up -d plugin_daemon 115 | ``` 116 | 117 | 118 | #### 3. How to install the offline version 如何安装离线版本 119 | 120 | Scripting tool for downloading Dify plugin package from Dify Marketplace and Github and repackaging [true] offline package (contains dependencies, no need to be connected to the Internet). 121 | 122 | 从Dify市场和Github下载Dify插件包并重新打【真】离线包(包含依赖,不需要再联网)的脚本工具。 123 | 124 | Github Repo: https://github.com/junjiem/dify-plugin-repackaging 125 | 126 | -------------------------------------------------------------------------------- /db_query/_assets/db_query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query/_assets/db_query.png -------------------------------------------------------------------------------- /db_query/_assets/db_query_chatflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query/_assets/db_query_chatflow.png -------------------------------------------------------------------------------- /db_query/_assets/db_query_sql_query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query/_assets/db_query_sql_query.png -------------------------------------------------------------------------------- /db_query/_assets/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db_query/_assets/llm_riddles1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query/_assets/llm_riddles1.png -------------------------------------------------------------------------------- /db_query/_assets/llm_riddles2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query/_assets/llm_riddles2.png -------------------------------------------------------------------------------- /db_query/_assets/llm_riddles3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query/_assets/llm_riddles3.png -------------------------------------------------------------------------------- /db_query/main.py: -------------------------------------------------------------------------------- 1 | from dify_plugin import Plugin, DifyPluginEnv 2 | 3 | plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120)) 4 | 5 | if __name__ == "__main__": 6 | plugin.run() 7 | -------------------------------------------------------------------------------- /db_query/manifest.yaml: -------------------------------------------------------------------------------- 1 | author: junjiem 2 | created_at: "2025-01-13T09:55:01.5573645+08:00" 3 | description: 4 | en_US: Database Query Utils. 5 | zh_Hans: 数据库查询工具。 6 | icon: icon.svg 7 | label: 8 | en_US: Database Query 9 | zh_Hans: 数据库查询 10 | meta: 11 | arch: 12 | - amd64 13 | - arm64 14 | runner: 15 | entrypoint: main 16 | language: python 17 | version: "3.12" 18 | version: 0.0.1 19 | name: db_query 20 | plugins: 21 | tools: 22 | - provider/db_query.yaml 23 | resource: 24 | memory: 1048576 25 | permission: 26 | model: 27 | enabled: true 28 | llm: true 29 | tool: 30 | enabled: true 31 | tags: 32 | - search 33 | - utilities 34 | type: plugin 35 | version: 0.0.9 36 | privacy: PRIVACY.md 37 | verified: false -------------------------------------------------------------------------------- /db_query/provider/db_query.py: -------------------------------------------------------------------------------- 1 | from dify_plugin import ToolProvider 2 | 3 | 4 | class DbQueryProvider(ToolProvider): 5 | def _validate_credentials(self, credentials: dict) -> None: 6 | pass 7 | -------------------------------------------------------------------------------- /db_query/provider/db_query.yaml: -------------------------------------------------------------------------------- 1 | extra: 2 | python: 3 | source: provider/db_query.py 4 | identity: 5 | name: db_query 6 | author: junjiem 7 | label: 8 | en_US: Database Query 9 | zh_Hans: 数据库查询 10 | description: 11 | en_US: Database Query Utils. 12 | zh_Hans: 数据库查询工具。 13 | icon: icon.svg 14 | tags: 15 | - search 16 | - utilities 17 | tools: 18 | - tools/sql_query.yaml -------------------------------------------------------------------------------- /db_query/requirements.txt: -------------------------------------------------------------------------------- 1 | dify_plugin==0.2.1 2 | sqlparse==0.5.3 3 | tabulate==0.9.0 4 | pandas==2.2.3 5 | SQLAlchemy==2.0.35 6 | PyMySQL==1.1.1 7 | oracledb==2.2.1 8 | psycopg2-binary==2.9.10 9 | pymssql==2.3.4 -------------------------------------------------------------------------------- /db_query/tools/db_util.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import logging 3 | from typing import Optional 4 | from urllib import parse 5 | from uuid import UUID 6 | 7 | import oracledb 8 | import pandas as pd 9 | from pandas import Timestamp 10 | from sqlalchemy import create_engine 11 | 12 | 13 | class DbUtil: 14 | 15 | def __init__(self, db_type: str, 16 | username: str, password: str, 17 | host: str, port: Optional[str] = None, 18 | database: Optional[str] = None, 19 | properties: Optional[str] = None) -> None: 20 | self.db_type = db_type.lower() 21 | self.username = username 22 | self.password = password 23 | self.host = host 24 | self.port = port 25 | self.database = database 26 | self.properties = properties 27 | if self.db_type == 'oracle11g': 28 | # To change from the default python-oracledb Thin mode to Thick mode 29 | oracledb.init_oracle_client() 30 | self.engine = create_engine(self.get_url(), pool_size=100, pool_recycle=36) 31 | 32 | def __enter__(self): 33 | return self 34 | 35 | def __exit__(self, exc_type, exc_val, exc_tb): 36 | self.close() 37 | 38 | def get_driver_name(self): 39 | driver_name = self.db_type 40 | if self.db_type == 'mysql': 41 | driver_name = 'mysql+pymysql' 42 | elif self.db_type in {'oracle', 'oracle11g'}: 43 | driver_name = 'oracle+oracledb' 44 | elif self.db_type == 'postgresql': 45 | driver_name = 'postgresql+psycopg2' 46 | elif self.db_type == 'mssql': 47 | driver_name = 'mssql+pymssql' 48 | return driver_name 49 | 50 | def get_url(self): 51 | ''' 52 | Get url 53 | ''' 54 | parsed_username = parse.quote_plus(self.username) 55 | parsed_password = parse.quote_plus(self.password) 56 | parsed_host = parse.quote_plus(self.host) 57 | url = f"{self.get_driver_name()}://{parsed_username}:{parsed_password}@{parsed_host}" 58 | if self.is_not_empty(self.port): 59 | url = f"{url}:{str(self.port)}" 60 | url = f"{url}/" 61 | if self.is_not_empty(self.database): 62 | parsed_database = parse.quote_plus(self.database) 63 | url = f"{url}{parsed_database}" 64 | if self.is_not_empty(self.properties): 65 | url = f"{url}?{self.properties}" 66 | logging.info(f"url: {url}") 67 | return url 68 | 69 | def close(self): 70 | """Close all connections in the engine.""" 71 | self.engine.dispose() 72 | 73 | def run_query(self, query_sql: str) -> list[dict]: 74 | ''' 75 | Run SQL Query 76 | ''' 77 | query_sql = query_sql.replace('%', '%%') 78 | df = pd.read_sql_query(sql=query_sql, con=self.engine, parse_dates="%Y-%m-%d %H:%M:%S") 79 | df = df.fillna('') 80 | records = [] 81 | if len(df) > 0: 82 | records = df.to_dict(orient="records") 83 | for record in records: 84 | for key in record: 85 | if type(record[key]) is Timestamp: 86 | record[key] = record[key].strftime('%Y-%m-%d %H:%M:%S') 87 | if type(record[key]) is datetime.date: 88 | record[key] = record[key].strftime('%Y-%m-%d') 89 | if type(record[key]) is UUID: 90 | record[key] = str(record[key]) 91 | return records 92 | 93 | def test_sql(self): 94 | if self.db_type in {'oracle', 'oracle11g'}: 95 | return "SELECT 1 FROM DUAL" 96 | else: 97 | return "SELECT 1" 98 | 99 | @staticmethod 100 | def is_not_empty(s: str): 101 | return s is not None and s.strip() != "" 102 | -------------------------------------------------------------------------------- /db_query/tools/sql_query.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Any, Generator 3 | 4 | import sqlparse 5 | import tabulate 6 | from dify_plugin import Tool 7 | from dify_plugin.entities.tool import ToolInvokeMessage 8 | 9 | from tools.db_util import DbUtil 10 | 11 | 12 | class SqlQueryTool(Tool): 13 | def _invoke( 14 | self, tool_parameters: dict[str, Any] 15 | ) -> Generator[ToolInvokeMessage, None, None]: 16 | """ 17 | invoke tools 18 | """ 19 | db_type = tool_parameters.get("db_type", "") 20 | if not db_type: 21 | raise ValueError("Please select the database type") 22 | db_host = tool_parameters.get("db_host", "") 23 | if not db_host: 24 | raise ValueError("Please fill in the database host") 25 | db_port = tool_parameters.get("db_port", "") 26 | if db_port is not None: 27 | db_port = str(db_port) 28 | db_username = tool_parameters.get("db_username", "") 29 | if not db_username: 30 | raise ValueError("Please fill in the database username") 31 | db_password = tool_parameters.get("db_password", "") 32 | if not db_password: 33 | raise ValueError("Please fill in the database password") 34 | db_name = tool_parameters.get("db_name", "") 35 | db_properties = tool_parameters.get("db_properties", "") 36 | 37 | query_sql = tool_parameters.get("query_sql", "") 38 | if not query_sql: 39 | raise ValueError("Please fill in the query SQL, for example: select * from tbl_name") 40 | statements = sqlparse.parse(query_sql) 41 | if len(statements) != 1: 42 | raise ValueError("Only a single query SQL can be filled") 43 | statement = statements[0] 44 | if statement.get_type() != 'SELECT': 45 | raise ValueError("Query SQL can only be a single SELECT statement") 46 | 47 | output_format = tool_parameters.get("output_format", "markdown").lower() 48 | 49 | try: 50 | with DbUtil(db_type=db_type, 51 | username=db_username, password=db_password, 52 | host=db_host, port=db_port, 53 | database=db_name, properties=db_properties) as db: 54 | records = db.run_query(query_sql) 55 | except Exception as e: 56 | logging.exception("SQL query execution failed: %s", str(e)) 57 | raise RuntimeError(f"Error executing SQL: {e}") from e 58 | 59 | if output_format == "json": 60 | yield self.create_json_message({"records": records}) 61 | else: 62 | text = tabulate.tabulate(records, headers="keys", tablefmt="github", floatfmt="") 63 | yield self.create_text_message(text) 64 | -------------------------------------------------------------------------------- /db_query/tools/sql_query.yaml: -------------------------------------------------------------------------------- 1 | identity: 2 | name: sql_query 3 | author: junjiem 4 | label: 5 | en_US: SQL Query 6 | zh_Hans: SQL查询 7 | description: 8 | human: 9 | en_US: A tool for Database SQL query. 10 | zh_Hans: 数据库SQL查询工具。 11 | llm: A tool for executing SQL query. Input should be a search query. 12 | extra: 13 | python: 14 | source: tools/sql_query.py 15 | parameters: 16 | - name: db_type 17 | type: select 18 | required: true 19 | options: 20 | - value: mysql 21 | label: 22 | en_US: MySQL 23 | zh_Hans: MySQL 24 | - value: oracle 25 | label: 26 | en_US: Oracle 27 | zh_Hans: Oracle 28 | - value: oracle11g 29 | label: 30 | en_US: Oracle11g 31 | zh_Hans: Oracle11g 32 | - value: postgresql 33 | label: 34 | en_US: PostgreSQL 35 | zh_Hans: PostgreSQL 36 | - value: mssql 37 | label: 38 | en_US: Microsoft SQL Server 39 | zh_Hans: Microsoft SQL Server 40 | default: mysql 41 | label: 42 | en_US: Database type 43 | zh_Hans: 数据库类型 44 | human_description: 45 | en_US: Used for selecting the database type, mysql, oracle, oracle11g, postgresql or mssql. 46 | zh_Hans: 用于选择数据库类型,mysql、oracle、oracle11g、postgresql或mssql。 47 | form: llm 48 | - name: db_host 49 | type: string 50 | required: true 51 | default: localhost 52 | label: 53 | en_US: Database Host 54 | zh_Hans: 数据库地址 55 | human_description: 56 | en_US: Database hostname or IP address (Original string, not URL-encoded string). 57 | zh_Hans: 数据库的主机名或IP地址(原始字符串,非URL编码字符串)。 58 | form: llm 59 | - name: db_port 60 | type: number 61 | required: false 62 | label: 63 | en_US: Port 64 | zh_Hans: 端口 65 | human_description: 66 | en_US: Database port. 67 | zh_Hans: 数据库的端口。 68 | form: llm 69 | - name: db_username 70 | type: string 71 | required: true 72 | label: 73 | en_US: Username 74 | zh_Hans: 用户名 75 | human_description: 76 | en_US: Database username (Original string, not URL-encoded string). 77 | zh_Hans: 数据库的用户名(原始字符串,非URL编码字符串)。 78 | form: llm 79 | - name: db_password 80 | type: secret-input 81 | required: true 82 | label: 83 | en_US: Password 84 | zh_Hans: 密码 85 | human_description: 86 | en_US: Database password (Original string, not URL-encoded string). 87 | zh_Hans: 数据库的密码(原始字符串,非URL编码字符串)。 88 | form: llm 89 | - name: db_name 90 | type: string 91 | required: false 92 | label: 93 | en_US: Database name 94 | zh_Hans: 库名 95 | human_description: 96 | en_US: Database name (Original string, not URL-encoded string). 97 | zh_Hans: 数据库的名称(原始字符串,非URL编码字符串)。 98 | form: llm 99 | - name: db_properties 100 | type: string 101 | required: false 102 | label: 103 | en_US: Database properties 104 | zh_Hans: 数据库属性 105 | human_description: 106 | en_US: 'Database properties, for example: alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt' 107 | zh_Hans: '数据库属性,例如:alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt' 108 | form: llm 109 | - name: query_sql 110 | type: string 111 | required: true 112 | label: 113 | en_US: Query SQL 114 | zh_Hans: SQL查询语句 115 | human_description: 116 | en_US: 'SQL query statement, for example: select * from tbl_name' 117 | zh_Hans: SQL查询语句,例如:select * from tbl_name 118 | llm_description: 'SQL query statement, for example: select * from tbl_name' 119 | form: llm 120 | - name: output_format 121 | type: select 122 | required: true 123 | label: 124 | en_US: Output format 125 | zh_Hans: 输出格式 126 | human_description: 127 | en_US: Used for selecting the output format, markdown or json. 128 | zh_Hans: 用于选择输出格式,markdown或json。 129 | options: 130 | - value: markdown 131 | label: 132 | en_US: MARKDOWN 133 | zh_Hans: MARKDOWN 134 | - value: json 135 | label: 136 | en_US: JSON 137 | zh_Hans: JSON 138 | default: markdown 139 | form: form -------------------------------------------------------------------------------- /db_query_pre_auth/.difyignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Distribution / packaging 7 | .Python 8 | build/ 9 | develop-eggs/ 10 | dist/ 11 | downloads/ 12 | eggs/ 13 | .eggs/ 14 | lib/ 15 | lib64/ 16 | parts/ 17 | sdist/ 18 | var/ 19 | wheels/ 20 | share/python-wheels/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | MANIFEST 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .nox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *.cover 46 | *.py,cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | cover/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | db.sqlite3-journal 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | .pybuilder/ 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # IPython 79 | profile_default/ 80 | ipython_config.py 81 | 82 | # pyenv 83 | # For a library or package, you might want to ignore these files since the code is 84 | # intended to run in multiple environments; otherwise, check them in: 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | Pipfile.lock 93 | 94 | # UV 95 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 96 | # This is especially recommended for binary packages to ensure reproducibility, and is more 97 | # commonly ignored for libraries. 98 | uv.lock 99 | 100 | # poetry 101 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 102 | # This is especially recommended for binary packages to ensure reproducibility, and is more 103 | # commonly ignored for libraries. 104 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 105 | poetry.lock 106 | 107 | # pdm 108 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 109 | #pdm.lock 110 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 111 | # in version control. 112 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 113 | .pdm.toml 114 | .pdm-python 115 | .pdm-build/ 116 | 117 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 118 | __pypackages__/ 119 | 120 | # Celery stuff 121 | celerybeat-schedule 122 | celerybeat.pid 123 | 124 | # SageMath parsed files 125 | *.sage.py 126 | 127 | # Environments 128 | .env 129 | .venv 130 | env/ 131 | venv/ 132 | ENV/ 133 | env.bak/ 134 | venv.bak/ 135 | 136 | # Spyder project settings 137 | .spyderproject 138 | .spyproject 139 | 140 | # Rope project settings 141 | .ropeproject 142 | 143 | # mkdocs documentation 144 | /site 145 | 146 | # mypy 147 | .mypy_cache/ 148 | .dmypy.json 149 | dmypy.json 150 | 151 | # Pyre type checker 152 | .pyre/ 153 | 154 | # pytype static type analyzer 155 | .pytype/ 156 | 157 | # Cython debug symbols 158 | cython_debug/ 159 | 160 | # PyCharm 161 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 162 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 163 | # and can be added to the global gitignore or merged into this file. For a more nuclear 164 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 165 | .idea/ 166 | 167 | # Vscode 168 | .vscode/ 169 | 170 | # Git 171 | .git/ 172 | .gitignore 173 | 174 | # Mac 175 | .DS_Store 176 | 177 | # Windows 178 | Thumbs.db 179 | -------------------------------------------------------------------------------- /db_query_pre_auth/.env.example: -------------------------------------------------------------------------------- 1 | INSTALL_METHOD=remote 2 | REMOTE_INSTALL_HOST=debug-plugin.dify.dev 3 | REMOTE_INSTALL_PORT=5003 4 | REMOTE_INSTALL_KEY=********-****-****-****-************ 5 | -------------------------------------------------------------------------------- /db_query_pre_auth/.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 | # UV 98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | #uv.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 116 | .pdm.toml 117 | .pdm-python 118 | .pdm-build/ 119 | 120 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 121 | __pypackages__/ 122 | 123 | # Celery stuff 124 | celerybeat-schedule 125 | celerybeat.pid 126 | 127 | # SageMath parsed files 128 | *.sage.py 129 | 130 | # Environments 131 | .env 132 | .venv 133 | env/ 134 | venv/ 135 | ENV/ 136 | env.bak/ 137 | venv.bak/ 138 | 139 | # Spyder project settings 140 | .spyderproject 141 | .spyproject 142 | 143 | # Rope project settings 144 | .ropeproject 145 | 146 | # mkdocs documentation 147 | /site 148 | 149 | # mypy 150 | .mypy_cache/ 151 | .dmypy.json 152 | dmypy.json 153 | 154 | # Pyre type checker 155 | .pyre/ 156 | 157 | # pytype static type analyzer 158 | .pytype/ 159 | 160 | # Cython debug symbols 161 | cython_debug/ 162 | 163 | # PyCharm 164 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 165 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 166 | # and can be added to the global gitignore or merged into this file. For a more nuclear 167 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 168 | .idea/ 169 | 170 | # Vscode 171 | .vscode/ 172 | -------------------------------------------------------------------------------- /db_query_pre_auth/GUIDE.md: -------------------------------------------------------------------------------- 1 | ## User Guide of how to develop a Dify Plugin 2 | 3 | Hi there, looks like you have already created a Plugin, now let's get you started with the development! 4 | 5 | ### Choose a Plugin type you want to develop 6 | 7 | Before start, you need some basic knowledge about the Plugin types, Plugin supports to extend the following abilities in Dify: 8 | - **Tool**: Tool Providers like Google Search, Stable Diffusion, etc. it can be used to perform a specific task. 9 | - **Model**: Model Providers like OpenAI, Anthropic, etc. you can use their models to enhance the AI capabilities. 10 | - **Endpoint**: Like Service API in Dify and Ingress in Kubernetes, you can extend a http service as an endpoint and control its logics using your own code. 11 | 12 | Based on the ability you want to extend, we have divided the Plugin into three types: **Tool**, **Model**, and **Extension**. 13 | 14 | - **Tool**: It's a tool provider, but not only limited to tools, you can implement an endpoint there, for example, you need both `Sending Message` and `Receiving Message` if you are building a Discord Bot, **Tool** and **Endpoint** are both required. 15 | - **Model**: Just a model provider, extending others is not allowed. 16 | - **Extension**: Other times, you may only need a simple http service to extend the functionalities, **Extension** is the right choice for you. 17 | 18 | I believe you have chosen the right type for your Plugin while creating it, if not, you can change it later by modifying the `manifest.yaml` file. 19 | 20 | ### Manifest 21 | 22 | Now you can edit the `manifest.yaml` file to describe your Plugin, here is the basic structure of it: 23 | 24 | - version(version, required):Plugin's version 25 | - type(type, required):Plugin's type, currently only supports `plugin`, future support `bundle` 26 | - author(string, required):Author, it's the organization name in Marketplace and should also equals to the owner of the repository 27 | - label(label, required):Multi-language name 28 | - created_at(RFC3339, required):Creation time, Marketplace requires that the creation time must be less than the current time 29 | - icon(asset, required):Icon path 30 | - resource (object):Resources to be applied 31 | - memory (int64):Maximum memory usage, mainly related to resource application on SaaS for serverless, unit bytes 32 | - permission(object):Permission application 33 | - tool(object):Reverse call tool permission 34 | - enabled (bool) 35 | - model(object):Reverse call model permission 36 | - enabled(bool) 37 | - llm(bool) 38 | - text_embedding(bool) 39 | - rerank(bool) 40 | - tts(bool) 41 | - speech2text(bool) 42 | - moderation(bool) 43 | - node(object):Reverse call node permission 44 | - enabled(bool) 45 | - endpoint(object):Allow to register endpoint permission 46 | - enabled(bool) 47 | - app(object):Reverse call app permission 48 | - enabled(bool) 49 | - storage(object):Apply for persistent storage permission 50 | - enabled(bool) 51 | - size(int64):Maximum allowed persistent memory, unit bytes 52 | - plugins(object, required):Plugin extension specific ability yaml file list, absolute path in the plugin package, if you need to extend the model, you need to define a file like openai.yaml, and fill in the path here, and the file on the path must exist, otherwise the packaging will fail. 53 | - Format 54 | - tools(list[string]): Extended tool suppliers, as for the detailed format, please refer to [Tool Guide](https://docs.dify.ai/docs/plugins/standard/tool_provider) 55 | - models(list[string]):Extended model suppliers, as for the detailed format, please refer to [Model Guide](https://docs.dify.ai/docs/plugins/standard/model_provider) 56 | - endpoints(list[string]):Extended Endpoints suppliers, as for the detailed format, please refer to [Endpoint Guide](https://docs.dify.ai/docs/plugins/standard/endpoint_group) 57 | - Restrictions 58 | - Not allowed to extend both tools and models 59 | - Not allowed to have no extension 60 | - Not allowed to extend both models and endpoints 61 | - Currently only supports up to one supplier of each type of extension 62 | - meta(object) 63 | - version(version, required):manifest format version, initial version 0.0.1 64 | - arch(list[string], required):Supported architectures, currently only supports amd64 arm64 65 | - runner(object, required):Runtime configuration 66 | - language(string):Currently only supports python 67 | - version(string):Language version, currently only supports 3.12 68 | - entrypoint(string):Program entry, in python it should be main 69 | 70 | ### Install Dependencies 71 | 72 | - First of all, you need a Python 3.11+ environment, as our SDK requires that. 73 | - Then, install the dependencies: 74 | ```bash 75 | pip install -r requirements.txt 76 | ``` 77 | - If you want to add more dependencies, you can add them to the `requirements.txt` file, once you have set the runner to python in the `manifest.yaml` file, `requirements.txt` will be automatically generated and used for packaging and deployment. 78 | 79 | ### Implement the Plugin 80 | 81 | Now you can start to implement your Plugin, by following these examples, you can quickly understand how to implement your own Plugin: 82 | 83 | - [OpenAI](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/openai): best practice for model provider 84 | - [Google Search](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/google): a simple example for tool provider 85 | - [Neko](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko): a funny example for endpoint group 86 | 87 | ### Test and Debug the Plugin 88 | 89 | You may already noticed that a `.env.example` file in the root directory of your Plugin, just copy it to `.env` and fill in the corresponding values, there are some environment variables you need to set if you want to debug your Plugin locally. 90 | 91 | - `INSTALL_METHOD`: Set this to `remote`, your plugin will connect to a Dify instance through the network. 92 | - `REMOTE_INSTALL_HOST`: The host of your Dify instance, you can use our SaaS instance `https://debug.dify.ai`, or self-hosted Dify instance. 93 | - `REMOTE_INSTALL_PORT`: The port of your Dify instance, default is 5003 94 | - `REMOTE_INSTALL_KEY`: You should get your debugging key from the Dify instance you used, at the right top of the plugin management page, you can see a button with a `debug` icon, click it and you will get the key. 95 | 96 | Run the following command to start your Plugin: 97 | 98 | ```bash 99 | python -m main 100 | ``` 101 | 102 | Refresh the page of your Dify instance, you should be able to see your Plugin in the list now, but it will be marked as `debugging`, you can use it normally, but not recommended for production. 103 | 104 | ### Package the Plugin 105 | 106 | After all, just package your Plugin by running the following command: 107 | 108 | ```bash 109 | dify-plugin plugin package ./ROOT_DIRECTORY_OF_YOUR_PLUGIN 110 | ``` 111 | 112 | you will get a `plugin.difypkg` file, that's all, you can submit it to the Marketplace now, look forward to your Plugin being listed! 113 | 114 | 115 | ## User Privacy Policy 116 | 117 | Please fill in the privacy policy of the plugin if you want to make it published on the Marketplace, refer to [PRIVACY.md](PRIVACY.md) for more details. -------------------------------------------------------------------------------- /db_query_pre_auth/PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | This tool is designed with privacy in mind and does not collect any user data. We are committed to maintaining your privacy and ensuring your data remains secure. 4 | 5 | ## Data Collection 6 | 7 | - **No Personal Information**: We do not collect, store, or process any personal information. 8 | - **No Usage Data**: We do not track or monitor how you use the tool. 9 | - **No Analytics**: We do not implement any analytics or tracking mechanisms. 10 | 11 | ## Third-Party Services 12 | 13 | This tool does not integrate with or utilize any third-party services that might collect user data. 14 | 15 | ## Changes to Privacy Policy 16 | 17 | If there are any changes to our privacy practices, we will update this document accordingly. -------------------------------------------------------------------------------- /db_query_pre_auth/README.md: -------------------------------------------------------------------------------- 1 | ## Dify 1.0 Plugin Database Query Tools (Pre-authorization) 2 | 3 | 4 | **Author:** [Junjie.M](https://github.com/junjiem) 5 | **Type:** tool 6 | **Github Repo:** [https://github.com/junjiem/dify-plugin-tools-dbquery](https://github.com/junjiem/dify-plugin-tools-dbquery) 7 | **Github Issues:** [issues](https://github.com/junjiem/dify-plugin-tools-dbquery/issues) 8 | 9 | 10 | --- 11 | 12 | 13 | ### Demonstration 14 | 15 | Database Query Tools (Pre-authorization) 16 | 17 | 数据库查询工具(预授权) 18 | 19 | Currently supported database types: mysql, oracle, [oracle11g](#2-how-to-connect-to-oracle-11g--如何连接oracle-11g), postgresql, or mssql. 20 | 21 | 目前支持的数据库类型:mysql、oracle、[oracle11g](#2-how-to-connect-to-oracle-11g--如何连接oracle-11g)、postgresql、mssql。 22 | 23 |  24 | 25 |  26 | 27 | 28 | 29 | --- 30 | 31 | 32 | 33 | ### Examples 示例 34 | 35 | - [完蛋!我被LLM包围了!(Dify1.0战绩排行版)](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/examples/完蛋!我被LLM包围了!(Dify1.0战绩排行版).yml) 36 | 37 | - [完蛋!我被LLM包围了!(Dify1.0战绩排行+留言版)](https://github.com/junjiem/dify-plugin-tools-dbquery/blob/main/examples/完蛋!我被LLM包围了!(Dify1.0战绩排行+留言版).yml) 38 | 39 | 40 |  41 | 42 |  43 | 44 |  45 | 46 | 47 | 48 | --- 49 | 50 | 51 | 52 | ### FAQ 53 | 54 | #### 1. How to Handle Errors When Installing Plugins? 安装插件时遇到异常应如何处理? 55 | 56 | **Issue**: If you encounter the error message: plugin verification has been enabled, and the plugin you want to install has a bad signature, how to handle the issue? 57 | 58 | **Solution**: Add the following line to the end of your .env configuration file: FORCE_VERIFYING_SIGNATURE=false 59 | Once this field is added, the Dify platform will allow the installation of all plugins that are not listed (and thus not verified) in the Dify Marketplace. 60 | 61 | **问题描述**:安装插件时遇到异常信息:plugin verification has been enabled, and the plugin you want to install has a bad signature,应该如何处理? 62 | 63 | **解决办法**:在 .env 配置文件的末尾添加 FORCE_VERIFYING_SIGNATURE=false 字段即可解决该问题。 64 | 添加该字段后,Dify 平台将允许安装所有未在 Dify Marketplace 上架(审核)的插件,可能存在安全隐患。 65 | 66 | 67 | #### 2. How to connect to oracle 11g 如何连接Oracle 11g 68 | 69 | 2.1、下载 oracle11g 的 client,这里下的是 11.2.0.4.0 版本 70 | 71 | https://www.oracle.com/database/technologies/instant-client/downloads.html 72 | 73 | 比如:instantclient-basic-linux.x64-11.2.0.4.0.zip 74 | 75 | 76 | 2.2、上传 oracle 的 client 到宿主机的 dify 的挂载目录 77 | 78 | 将 instantclient-basic-linux.x64-11.2.0.4.0.zip 解压后的 instantclient_11_2 目录放到 docker/volumes 下面 79 | > 注:需要将 `instantclient_11_2` 中`libclntsh.so.11.1` 改成 `libclntsh.so`、 `libocci.so.11.1` 改成 `libocci.so` 80 | 81 | 2.3、在 `docker/docker-compose.yml` 中进行配置 82 | ``` 83 | # 在 plugin_daemon 下,添加一个变量 84 | environment: 85 | ...... 86 | LD_LIBRARY_PATH: "/root/instantclient_11_2:$LD_LIBRARY_PATH" 87 | ``` 88 | 89 | Red Hat 系(如 CentOS、RHEL)64 位: 90 | ``` 91 | # 在 plugin_daemon 下,添加三个挂载 92 | volumes: 93 | ...... 94 | - ./volumes/instantclient_11_2:/root/instantclient_11_2 95 | - /usr/lib64/libaio.so.1.0.1:/usr/lib/x86_64-linux-gnu/libaio.so.1.0.1 96 | - /usr/lib64/libaio.so.1:/usr/lib/x86_64-linux-gnu/libaio.so.1 97 | ``` 98 | 99 | Debian 系(如 Ubuntu)64 位: 100 | ``` 101 | # 在 plugin_daemon 下,添加三个挂载 102 | volumes: 103 | ...... 104 | - ./volumes/instantclient_11_2:/root/instantclient_11_2 105 | - /usr/lib/x86_64-linux-gnu/libaio.so.1.0.1:/usr/lib/x86_64-linux-gnu/libaio.so.1.0.1 106 | - /usr/lib/x86_64-linux-gnu/libaio.so.1:/usr/lib/x86_64-linux-gnu/libaio.so.1 107 | ``` 108 | 109 | 2.4、重启 plugin_daemon 110 | ```shell 111 | docker stop docker-plugin_daemon-1 112 | docker compose up -d plugin_daemon 113 | ``` 114 | 115 | 116 | #### 3. How to install the offline version 如何安装离线版本 117 | 118 | Scripting tool for downloading Dify plugin package from Dify Marketplace and Github and repackaging [true] offline package (contains dependencies, no need to be connected to the Internet). 119 | 120 | 从Dify市场和Github下载Dify插件包并重新打【真】离线包(包含依赖,不需要再联网)的脚本工具。 121 | 122 | Github Repo: https://github.com/junjiem/dify-plugin-repackaging 123 | 124 | -------------------------------------------------------------------------------- /db_query_pre_auth/_assets/db_query_pre_auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query_pre_auth/_assets/db_query_pre_auth.png -------------------------------------------------------------------------------- /db_query_pre_auth/_assets/db_query_pre_auth_setup_auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query_pre_auth/_assets/db_query_pre_auth_setup_auth.png -------------------------------------------------------------------------------- /db_query_pre_auth/_assets/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db_query_pre_auth/_assets/llm_riddles1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query_pre_auth/_assets/llm_riddles1.png -------------------------------------------------------------------------------- /db_query_pre_auth/_assets/llm_riddles2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query_pre_auth/_assets/llm_riddles2.png -------------------------------------------------------------------------------- /db_query_pre_auth/_assets/llm_riddles3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/junjiem/dify-plugin-tools-dbquery/23d3f2983a97dbb3bbbaaa4bf9067e2c2a38b7f2/db_query_pre_auth/_assets/llm_riddles3.png -------------------------------------------------------------------------------- /db_query_pre_auth/main.py: -------------------------------------------------------------------------------- 1 | from dify_plugin import Plugin, DifyPluginEnv 2 | 3 | plugin = Plugin(DifyPluginEnv(MAX_REQUEST_TIMEOUT=120)) 4 | 5 | if __name__ == "__main__": 6 | plugin.run() 7 | -------------------------------------------------------------------------------- /db_query_pre_auth/manifest.yaml: -------------------------------------------------------------------------------- 1 | name: db_query_pre_auth 2 | author: junjiem 3 | icon: icon.svg 4 | created_at: "2025-01-13T09:55:01.5573645+08:00" 5 | label: 6 | en_US: Database Query (Pre-authorization) 7 | zh_Hans: 数据库查询(预授权) 8 | description: 9 | en_US: Database Query Utils (Pre-authorization). 10 | zh_Hans: 数据库查询工具(预授权)。 11 | meta: 12 | arch: 13 | - amd64 14 | - arm64 15 | runner: 16 | entrypoint: main 17 | language: python 18 | version: "3.12" 19 | version: 0.0.1 20 | plugins: 21 | tools: 22 | - provider/db_query.yaml 23 | resource: 24 | memory: 1048576 25 | permission: 26 | model: 27 | enabled: true 28 | llm: true 29 | tool: 30 | enabled: true 31 | tags: 32 | - search 33 | - utilities 34 | type: plugin 35 | version: 0.0.9 36 | privacy: PRIVACY.md 37 | verified: false -------------------------------------------------------------------------------- /db_query_pre_auth/provider/db_query.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from dify_plugin import ToolProvider 4 | 5 | from tools.db_util import DbUtil 6 | 7 | 8 | class DbQueryProvider(ToolProvider): 9 | def _validate_credentials(self, credentials: dict) -> None: 10 | db_type = credentials.get("db_type", "") 11 | if not db_type: 12 | raise ValueError("Please select the database type") 13 | db_host = credentials.get("db_host", "") 14 | if not db_host: 15 | raise ValueError("Please fill in the database host") 16 | db_username = credentials.get("db_username", "") 17 | if not db_username: 18 | raise ValueError("Please fill in the database username") 19 | db_password = credentials.get("db_password", "") 20 | if not db_password: 21 | raise ValueError("Please fill in the database password") 22 | db_port = credentials.get("db_port", "") 23 | if DbUtil.is_not_empty(db_port) and not db_port.isdigit(): 24 | raise ValueError("Database port can be empty or fill with integer value") 25 | db_name = credentials.get("db_name", "") 26 | db_properties = credentials.get("db_properties", "") 27 | 28 | try: 29 | with DbUtil(db_type=db_type, 30 | username=db_username, password=db_password, 31 | host=db_host, port=db_port, 32 | database=db_name, properties=db_properties) as db: 33 | db.run_query(db.test_sql()) 34 | except Exception as e: 35 | logging.exception("Database connection failed: %s", str(e)) 36 | raise RuntimeError(f"Error connection database: {e}") from e 37 | -------------------------------------------------------------------------------- /db_query_pre_auth/provider/db_query.yaml: -------------------------------------------------------------------------------- 1 | extra: 2 | python: 3 | source: provider/db_query.py 4 | identity: 5 | name: db_query_pre_auth 6 | author: junjiem 7 | label: 8 | en_US: Database Query (Pre-authorization) 9 | zh_Hans: 数据库查询(预授权) 10 | description: 11 | en_US: Database Query Utils (Pre-authorization). 12 | zh_Hans: 数据库查询工具(预授权)。 13 | icon: icon.svg 14 | tags: 15 | - search 16 | - utilities 17 | tools: 18 | - tools/sql_query.yaml 19 | credentials_for_provider: 20 | db_type: 21 | type: select 22 | required: true 23 | options: 24 | - value: mysql 25 | label: 26 | en_US: MySQL 27 | zh_Hans: MySQL 28 | - value: oracle 29 | label: 30 | en_US: Oracle 31 | zh_Hans: Oracle 32 | - value: oracle11g 33 | label: 34 | en_US: Oracle11g 35 | zh_Hans: Oracle11g 36 | - value: postgresql 37 | label: 38 | en_US: PostgreSQL 39 | zh_Hans: PostgreSQL 40 | - value: mssql 41 | label: 42 | en_US: Microsoft SQL Server 43 | zh_Hans: Microsoft SQL Server 44 | default: mysql 45 | label: 46 | en_US: Database type 47 | zh_Hans: 数据库类型 48 | help: 49 | en_US: Used for selecting the database type, mysql, oracle, oracle11g, postgresql or mssql. 50 | zh_Hans: 用于选择数据库类型,mysql、oracle、oracle11g、postgresql或mssql。 51 | db_host: 52 | type: text-input 53 | required: true 54 | default: localhost 55 | label: 56 | en_US: Database Host 57 | zh_Hans: 数据库地址 58 | human_description: 59 | en_US: Database hostname or IP address (Original string, not URL-encoded string). 60 | zh_Hans: 数据库的主机名或IP地址(原始字符串,非URL编码字符串)。 61 | db_port: 62 | type: text-input 63 | required: false 64 | label: 65 | en_US: Port 66 | zh_Hans: 端口 67 | human_description: 68 | en_US: Database port (Original string, not URL-encoded string). 69 | zh_Hans: 数据库的端口(原始字符串,非URL编码字符串)。 70 | db_username: 71 | type: text-input 72 | required: true 73 | label: 74 | en_US: Username 75 | zh_Hans: 用户名 76 | human_description: 77 | en_US: Database username (Original string, not URL-encoded string). 78 | zh_Hans: 数据库的用户名(原始字符串,非URL编码字符串)。 79 | db_password: 80 | type: secret-input 81 | required: true 82 | label: 83 | en_US: Password 84 | zh_Hans: 密码 85 | human_description: 86 | en_US: Database password (Original string, not URL-encoded string). 87 | zh_Hans: 数据库的密码(原始字符串,非URL编码字符串)。 88 | db_name: 89 | type: text-input 90 | required: false 91 | label: 92 | en_US: Database name 93 | zh_Hans: 库名 94 | human_description: 95 | en_US: Database name. 96 | zh_Hans: 数据库的名称。 97 | db_properties: 98 | type: text-input 99 | required: false 100 | label: 101 | en_US: Database properties 102 | zh_Hans: 数据库属性 103 | human_description: 104 | en_US: 'Database properties, for example: alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt' 105 | zh_Hans: '数据库属性,例如:alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt' 106 | help: 107 | en_US: 'Database properties, for example: alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt' 108 | zh_Hans: '数据库属性,例如:alt_host=host1&alt_host=host2&ssl_cipher=%2Fpath%2Fto%2Fcrt' 109 | -------------------------------------------------------------------------------- /db_query_pre_auth/requirements.txt: -------------------------------------------------------------------------------- 1 | dify_plugin==0.2.1 2 | sqlparse==0.5.3 3 | tabulate==0.9.0 4 | pandas==2.2.3 5 | SQLAlchemy==2.0.35 6 | PyMySQL==1.1.1 7 | oracledb==2.2.1 8 | psycopg2-binary==2.9.10 9 | pymssql==2.3.4 -------------------------------------------------------------------------------- /db_query_pre_auth/tools/db_util.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import logging 3 | from typing import Optional 4 | from urllib import parse 5 | from uuid import UUID 6 | 7 | import oracledb 8 | import pandas as pd 9 | from pandas import Timestamp 10 | from sqlalchemy import create_engine 11 | 12 | 13 | class DbUtil: 14 | 15 | def __init__(self, db_type: str, 16 | username: str, password: str, 17 | host: str, port: Optional[str] = None, 18 | database: Optional[str] = None, 19 | properties: Optional[str] = None) -> None: 20 | self.db_type = db_type.lower() 21 | self.username = username 22 | self.password = password 23 | self.host = host 24 | self.port = port 25 | self.database = database 26 | self.properties = properties 27 | if self.db_type == 'oracle11g': 28 | # To change from the default python-oracledb Thin mode to Thick mode 29 | oracledb.init_oracle_client() 30 | self.engine = create_engine(self.get_url(), pool_size=100, pool_recycle=36) 31 | 32 | def __enter__(self): 33 | return self 34 | 35 | def __exit__(self, exc_type, exc_val, exc_tb): 36 | self.close() 37 | 38 | def get_driver_name(self): 39 | driver_name = self.db_type 40 | if self.db_type == 'mysql': 41 | driver_name = 'mysql+pymysql' 42 | elif self.db_type in {'oracle', 'oracle11g'}: 43 | driver_name = 'oracle+oracledb' 44 | elif self.db_type == 'postgresql': 45 | driver_name = 'postgresql+psycopg2' 46 | elif self.db_type == 'mssql': 47 | driver_name = 'mssql+pymssql' 48 | return driver_name 49 | 50 | def get_url(self): 51 | ''' 52 | Get url 53 | ''' 54 | parsed_username = parse.quote_plus(self.username) 55 | parsed_password = parse.quote_plus(self.password) 56 | parsed_host = parse.quote_plus(self.host) 57 | url = f"{self.get_driver_name()}://{parsed_username}:{parsed_password}@{parsed_host}" 58 | if self.is_not_empty(self.port): 59 | url = f"{url}:{str(self.port)}" 60 | url = f"{url}/" 61 | if self.is_not_empty(self.database): 62 | parsed_database = parse.quote_plus(self.database) 63 | url = f"{url}{parsed_database}" 64 | if self.is_not_empty(self.properties): 65 | url = f"{url}?{self.properties}" 66 | logging.info(f"url: {url}") 67 | return url 68 | 69 | def close(self): 70 | """Close all connections in the engine.""" 71 | self.engine.dispose() 72 | 73 | def run_query(self, query_sql: str) -> list[dict]: 74 | ''' 75 | Run SQL Query 76 | ''' 77 | query_sql = query_sql.replace('%', '%%') 78 | df = pd.read_sql_query(sql=query_sql, con=self.engine, parse_dates="%Y-%m-%d %H:%M:%S") 79 | df = df.fillna('') 80 | records = [] 81 | if len(df) > 0: 82 | records = df.to_dict(orient="records") 83 | for record in records: 84 | for key in record: 85 | if type(record[key]) is Timestamp: 86 | record[key] = record[key].strftime('%Y-%m-%d %H:%M:%S') 87 | if type(record[key]) is datetime.date: 88 | record[key] = record[key].strftime('%Y-%m-%d') 89 | if type(record[key]) is UUID: 90 | record[key] = str(record[key]) 91 | return records 92 | 93 | def test_sql(self): 94 | if self.db_type in {'oracle', 'oracle11g'}: 95 | return "SELECT 1 FROM DUAL" 96 | else: 97 | return "SELECT 1" 98 | 99 | @staticmethod 100 | def is_not_empty(s: str): 101 | return s is not None and s.strip() != "" 102 | -------------------------------------------------------------------------------- /db_query_pre_auth/tools/sql_query.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Any, Generator 3 | 4 | import sqlparse 5 | import tabulate 6 | from dify_plugin import Tool 7 | from dify_plugin.entities.tool import ToolInvokeMessage 8 | 9 | from tools.db_util import DbUtil 10 | 11 | 12 | class SqlQueryTool(Tool): 13 | def _invoke( 14 | self, tool_parameters: dict[str, Any] 15 | ) -> Generator[ToolInvokeMessage, None, None]: 16 | """ 17 | invoke tools 18 | """ 19 | db_type = self.runtime.credentials["db_type"] 20 | if not db_type: 21 | raise ValueError("Please select the database type") 22 | db_host = self.runtime.credentials["db_host"] 23 | if not db_host: 24 | raise ValueError("Please fill in the database host") 25 | db_port = self.runtime.credentials["db_port"] 26 | if DbUtil.is_not_empty(db_port) and not db_port.isdigit(): 27 | raise ValueError("Database port can be empty or fill with integer value") 28 | db_username = self.runtime.credentials["db_username"] 29 | if not db_username: 30 | raise ValueError("Please fill in the database username") 31 | db_password = self.runtime.credentials["db_password"] 32 | if not db_password: 33 | raise ValueError("Please fill in the database password") 34 | db_name = self.runtime.credentials["db_name"] 35 | db_properties = self.runtime.credentials["db_properties"] 36 | 37 | query_sql = tool_parameters.get("query_sql", "") 38 | if not query_sql: 39 | raise ValueError("Please fill in the query SQL, for example: select * from tbl_name") 40 | statements = sqlparse.parse(query_sql) 41 | if len(statements) != 1: 42 | raise ValueError("Only a single query SQL can be filled") 43 | statement = statements[0] 44 | if statement.get_type() != 'SELECT': 45 | raise ValueError("Query SQL can only be a single SELECT statement") 46 | 47 | output_format = tool_parameters.get("output_format", "markdown").lower() 48 | 49 | try: 50 | with DbUtil(db_type=db_type, 51 | username=db_username, password=db_password, 52 | host=db_host, port=db_port, 53 | database=db_name, properties=db_properties) as db: 54 | records = db.run_query(query_sql) 55 | except Exception as e: 56 | logging.exception("SQL query execution failed: %s", str(e)) 57 | raise RuntimeError(f"Error executing SQL: {e}") from e 58 | 59 | if output_format == "json": 60 | yield self.create_json_message({"records": records}) 61 | else: 62 | text = tabulate.tabulate(records, headers="keys", tablefmt="github", floatfmt="") 63 | yield self.create_text_message(text) -------------------------------------------------------------------------------- /db_query_pre_auth/tools/sql_query.yaml: -------------------------------------------------------------------------------- 1 | identity: 2 | name: sql_query_pre_auth 3 | author: junjiem 4 | label: 5 | en_US: SQL Query (Pre-authorization) 6 | zh_Hans: SQL查询(预授权) 7 | description: 8 | human: 9 | en_US: A tool for Database SQL query (Pre-authorization). 10 | zh_Hans: 数据库SQL查询工具(预授权)。 11 | llm: A tool for executing SQL query. Input should be a search query. 12 | extra: 13 | python: 14 | source: tools/sql_query.py 15 | parameters: 16 | - name: query_sql 17 | type: string 18 | required: true 19 | label: 20 | en_US: Query SQL 21 | zh_Hans: SQL查询语句 22 | human_description: 23 | en_US: 'SQL query statement, for example: select * from tbl_name' 24 | zh_Hans: SQL查询语句,例如:select * from tbl_name 25 | llm_description: 'SQL query statement, for example: select * from tbl_name' 26 | form: llm 27 | - name: output_format 28 | type: select 29 | required: true 30 | label: 31 | en_US: Output format 32 | zh_Hans: 输出格式 33 | human_description: 34 | en_US: Used for selecting the output format, markdown or json. 35 | zh_Hans: 用于选择输出格式,markdown或json。 36 | options: 37 | - value: markdown 38 | label: 39 | en_US: MARKDOWN 40 | zh_Hans: MARKDOWN 41 | - value: json 42 | label: 43 | en_US: JSON 44 | zh_Hans: JSON 45 | default: markdown 46 | form: form -------------------------------------------------------------------------------- /examples/完蛋!我被LLM包围了!(Dify1.0战绩排行版).yml: -------------------------------------------------------------------------------- 1 | app: 2 | description: '你可以和大模型斗智斗勇,通过你的聪明才智,让大模型遵循你的指令,“老老实实”地回答问题。 3 | 4 | 通过本游戏对大型语言模型产生更深刻的理解。一起来感受玩“坏”大模型的乐趣吧! 5 | 6 | 目前总共有五个章节:对话之趣、数字游戏、巅峰挑战、无人之境、登堂入室。每个章节有多个关卡,试试看你能通过几个章节,可能你连第一章都无法通过。' 7 | icon: video_game 8 | icon_background: '#FBE8FF' 9 | mode: advanced-chat 10 | name: 完蛋!我被LLM包围了!(战绩排行版) 11 | use_icon_as_answer_icon: true 12 | dependencies: 13 | - current_identifier: null 14 | type: marketplace 15 | value: 16 | marketplace_plugin_unique_identifier: junjiem/db_query_pre_auth:0.0.4@42ff23da07a60b140fbd3e2fbe1c282f8ecaf4cd7d4ba9a12874f02995d1fceb 17 | - current_identifier: null 18 | type: marketplace 19 | value: 20 | marketplace_plugin_unique_identifier: langgenius/tongyi:0.0.13@5a4c38f32498ab259b96833608a6a90c0b29671ecf14af272fbc7cde97e813d1 21 | kind: app 22 | version: 0.1.5 23 | workflow: 24 | conversation_variables: 25 | - description: 查看排行榜的时间戳(用于限制频繁查看排行榜消耗太多元数据库的计算资源) 26 | id: dcd81eb0-fbc0-4fce-88bc-a19ec6826f24 27 | name: show_ranking_ts 28 | selector: 29 | - conversation 30 | - show_ranking_ts 31 | value: 0 32 | value_type: number 33 | - description: 问题类型,0:普通问题,1:回文问题,2:互惠问题 34 | id: 025bffa8-5502-4639-b4c5-78e006217829 35 | name: question_type 36 | selector: 37 | - conversation 38 | - question_type 39 | value: 0 40 | value_type: number 41 | - description: 游戏状态(pending\start\running\restart\success) 42 | id: b380e461-c8e1-4d5f-be5f-439ddf84fc5a 43 | name: status 44 | selector: 45 | - conversation 46 | - status 47 | value: pending 48 | value_type: string 49 | - description: 问题序号 50 | id: 90d13fef-affa-4660-883f-00881df92f4c 51 | name: question_id 52 | selector: 53 | - conversation 54 | - question_id 55 | value: 0 56 | value_type: number 57 | - description: 游戏关卡 58 | id: d05c7f90-2e56-4296-9b91-4a481d44682e 59 | name: game_level 60 | selector: 61 | - conversation 62 | - game_level 63 | value: 0 64 | value_type: number 65 | environment_variables: 66 | - description: '' 67 | id: 81051d42-e73b-4d85-8d5d-59eed29f488c 68 | name: top_n 69 | selector: 70 | - env 71 | - top_n 72 | value: 50 73 | value_type: number 74 | features: 75 | file_upload: 76 | allowed_file_extensions: 77 | - .JPG 78 | - .JPEG 79 | - .PNG 80 | - .GIF 81 | - .WEBP 82 | - .SVG 83 | allowed_file_types: 84 | - image 85 | allowed_file_upload_methods: 86 | - local_file 87 | - remote_url 88 | enabled: false 89 | fileUploadConfig: 90 | audio_file_size_limit: 50 91 | batch_count_limit: 5 92 | file_size_limit: 15 93 | image_file_size_limit: 10 94 | video_file_size_limit: 100 95 | workflow_file_upload_limit: 10 96 | image: 97 | enabled: false 98 | number_limits: 3 99 | transfer_methods: 100 | - local_file 101 | - remote_url 102 | number_limits: 3 103 | opening_statement: '