├── api └── core │ ├── moderation │ └── cloud_service │ │ ├── __init__.py │ │ ├── schema.json │ │ └── cloud_service.py │ ├── external_data_tool │ └── weather_search │ │ ├── __init__.py │ │ ├── schema.json │ │ └── weather_search.py │ └── tools │ └── builtin_tool │ └── providers │ └── calculator │ ├── calculator.yaml │ ├── calculator.py │ ├── tools │ ├── add.yaml │ └── add.py │ └── _assets │ └── icon.svg ├── plugins ├── mockgpt │ ├── requirements.txt │ ├── PRIVACY.md │ ├── .env.example │ ├── README.md │ ├── main.py │ ├── manifest.yaml │ ├── models │ │ └── llm │ │ │ ├── llm.yaml │ │ │ └── llm.py │ ├── provider │ │ ├── demo.py │ │ └── demo.yaml │ ├── .gitignore │ ├── GUIDE.md │ ├── _assets │ │ ├── icon.svg │ │ └── icon-dark.svg │ ├── .difyignore │ └── .github │ │ └── workflows │ │ └── plugin-publish.yml ├── calculator │ ├── requirements.txt │ ├── PRIVACY.md │ ├── .env.example │ ├── README.md │ ├── main.py │ ├── provider │ │ ├── calculator.yaml │ │ └── calculator.py │ ├── tools │ │ ├── add.py │ │ └── add.yaml │ ├── manifest.yaml │ ├── _assets │ │ ├── icon.svg │ │ └── icon-dark.svg │ ├── .gitignore │ ├── GUIDE.md │ ├── .difyignore │ └── .github │ │ └── workflows │ │ └── plugin-publish.yml ├── demo.difypkg ├── calculator.difypkg ├── calculator.signed.difypkg ├── demo.public.pem └── demo.private.pem ├── README.md └── .gitignore /api/core/moderation/cloud_service/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/core/external_data_tool/weather_search/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugins/mockgpt/requirements.txt: -------------------------------------------------------------------------------- 1 | dify_plugin>=0.4.0,<0.7.0 2 | -------------------------------------------------------------------------------- /plugins/calculator/requirements.txt: -------------------------------------------------------------------------------- 1 | dify_plugin>=0.4.0,<0.7.0 2 | -------------------------------------------------------------------------------- /plugins/mockgpt/PRIVACY.md: -------------------------------------------------------------------------------- 1 | ## Privacy 2 | 3 | !!! Please fill in the privacy policy of the plugin. -------------------------------------------------------------------------------- /plugins/calculator/PRIVACY.md: -------------------------------------------------------------------------------- 1 | ## Privacy 2 | 3 | !!! Please fill in the privacy policy of the plugin. -------------------------------------------------------------------------------- /plugins/demo.difypkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aneasystone/dify-plugins/main/plugins/demo.difypkg -------------------------------------------------------------------------------- /plugins/calculator.difypkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aneasystone/dify-plugins/main/plugins/calculator.difypkg -------------------------------------------------------------------------------- /plugins/calculator.signed.difypkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aneasystone/dify-plugins/main/plugins/calculator.signed.difypkg -------------------------------------------------------------------------------- /plugins/mockgpt/.env.example: -------------------------------------------------------------------------------- 1 | INSTALL_METHOD=remote 2 | REMOTE_INSTALL_URL=debug.dify.ai:5003 3 | REMOTE_INSTALL_KEY=********-****-****-****-************ 4 | -------------------------------------------------------------------------------- /plugins/calculator/.env.example: -------------------------------------------------------------------------------- 1 | INSTALL_METHOD=remote 2 | REMOTE_INSTALL_URL=debug.dify.ai:5003 3 | REMOTE_INSTALL_KEY=********-****-****-****-************ 4 | -------------------------------------------------------------------------------- /plugins/mockgpt/README.md: -------------------------------------------------------------------------------- 1 | ## demo 2 | 3 | **Author:** aneasystone 4 | **Version:** 0.0.1 5 | **Type:** model 6 | 7 | ### Description 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /plugins/calculator/README.md: -------------------------------------------------------------------------------- 1 | ## calculator 2 | 3 | **Author:** aneasystone 4 | **Version:** 0.0.1 5 | **Type:** tool 6 | 7 | ### Description 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /plugins/calculator/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 | -------------------------------------------------------------------------------- /plugins/mockgpt/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 | -------------------------------------------------------------------------------- /api/core/tools/builtin_tool/providers/calculator/calculator.yaml: -------------------------------------------------------------------------------- 1 | identity: 2 | author: Dify 3 | name: calculator 4 | label: 5 | en_US: Calculator 6 | zh_Hans: 计算器 7 | description: 8 | en_US: Calculator 9 | zh_Hans: 计算器 10 | icon: icon.svg 11 | tags: 12 | - productivity 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Dify 插件学习示例 2 | 3 | ### 扩展 4 | 5 | - `api/core/external_data_tool`:外部工具扩展,自定义基于 API 的变量 6 | - `api/core/moderation`:内容审核扩展,自定义审核策略 7 | 8 | ### 内置工具 9 | 10 | - `api/core/tools/builtin_tool`:自定义内置工具 11 | 12 | ### 插件 13 | 14 | - `plugins/mockgpt`:自定义模型插件,简单的模拟流式输出 15 | - `plugins/calculator`:自定义工具插件,简单的计算器 16 | -------------------------------------------------------------------------------- /api/core/tools/builtin_tool/providers/calculator/calculator.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from core.tools.builtin_tool.provider import BuiltinToolProviderController 4 | 5 | 6 | class CalculatorToolProvider(BuiltinToolProviderController): 7 | def _validate_credentials(self, user_id: str, credentials: dict[str, Any]) -> None: 8 | pass 9 | -------------------------------------------------------------------------------- /plugins/calculator/provider/calculator.yaml: -------------------------------------------------------------------------------- 1 | identity: 2 | author: aneasystone 3 | name: calculator 4 | label: 5 | en_US: Calculator 6 | zh_Hans: 计算器 7 | description: 8 | en_US: Calculator 9 | zh_Hans: 计算器 10 | icon: icon.svg 11 | tools: 12 | - tools/add.yaml 13 | extra: 14 | python: 15 | source: provider/calculator.py 16 | -------------------------------------------------------------------------------- /plugins/calculator/tools/add.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Generator 2 | from typing import Any 3 | 4 | from dify_plugin import Tool 5 | from dify_plugin.entities.tool import ToolInvokeMessage 6 | 7 | class AddTool(Tool): 8 | 9 | def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage]: 10 | """ 11 | 加法运算 12 | """ 13 | 14 | x = tool_parameters.get("x", 0) 15 | y = tool_parameters.get("y", 0) 16 | 17 | result = str(x + y) 18 | yield self.create_text_message(result) 19 | -------------------------------------------------------------------------------- /plugins/calculator/manifest.yaml: -------------------------------------------------------------------------------- 1 | version: 0.0.1 2 | type: plugin 3 | author: aneasystone 4 | name: calculator 5 | label: 6 | en_US: Calculator 7 | zh_Hans: 计算器 8 | description: 9 | en_US: Calculator 10 | zh_Hans: 计算器 11 | icon: icon.svg 12 | icon_dark: icon-dark.svg 13 | resource: 14 | memory: 268435456 15 | permission: {} 16 | plugins: 17 | tools: 18 | - provider/calculator.yaml 19 | meta: 20 | version: 0.0.1 21 | arch: 22 | - amd64 23 | - arm64 24 | runner: 25 | language: python 26 | version: "3.12" 27 | entrypoint: main 28 | minimum_dify_version: null 29 | created_at: 2025-10-22T21:04:51.275866+08:00 30 | privacy: PRIVACY.md 31 | verified: false 32 | -------------------------------------------------------------------------------- /plugins/mockgpt/manifest.yaml: -------------------------------------------------------------------------------- 1 | version: 0.0.1 2 | type: plugin 3 | author: aneasystone 4 | name: demo 5 | label: 6 | en_US: Demo AI Provider 7 | zh_Hans: 演示 AI 供应商 8 | description: 9 | en_US: A demo AI model provider for learning 10 | zh_Hans: 用于学习的演示 AI 模型供应商 11 | icon: icon.svg 12 | icon_dark: icon-dark.svg 13 | resource: 14 | memory: 268435456 15 | permission: {} 16 | plugins: 17 | models: 18 | - provider/demo.yaml 19 | meta: 20 | version: 0.0.1 21 | arch: 22 | - amd64 23 | - arm64 24 | runner: 25 | language: python 26 | version: "3.12" 27 | entrypoint: main 28 | minimum_dify_version: null 29 | created_at: 2025-10-22T07:45:17.322263+08:00 30 | privacy: PRIVACY.md 31 | verified: false 32 | -------------------------------------------------------------------------------- /api/core/tools/builtin_tool/providers/calculator/tools/add.yaml: -------------------------------------------------------------------------------- 1 | identity: 2 | name: add 3 | author: Dify 4 | label: 5 | en_US: Add 6 | zh_Hans: 加法 7 | description: 8 | human: 9 | en_US: Calculate the value of x + y 10 | zh_Hans: 计算 x + y 的值 11 | llm: A tool for calculating the value of two numbers 12 | parameters: 13 | - name: x 14 | type: number 15 | required: true 16 | label: 17 | en_US: x 18 | zh_Hans: x 19 | human_description: 20 | en_US: x 21 | zh_Hans: x 22 | llm_description: x 23 | form: llm 24 | - name: y 25 | type: number 26 | required: true 27 | label: 28 | en_US: y 29 | zh_Hans: y 30 | human_description: 31 | en_US: y 32 | zh_Hans: y 33 | llm_description: y 34 | form: llm 35 | -------------------------------------------------------------------------------- /plugins/calculator/tools/add.yaml: -------------------------------------------------------------------------------- 1 | identity: 2 | name: add 3 | author: aneasystone 4 | label: 5 | en_US: Add 6 | zh_Hans: 加法 7 | description: 8 | human: 9 | en_US: Calculate the value of x + y 10 | zh_Hans: 计算 x + y 的值 11 | llm: A tool for calculating the value of two numbers 12 | parameters: 13 | - name: x 14 | type: number 15 | required: true 16 | label: 17 | en_US: x 18 | zh_Hans: x 19 | human_description: 20 | en_US: x 21 | zh_Hans: x 22 | llm_description: x 23 | form: llm 24 | - name: y 25 | type: number 26 | required: true 27 | label: 28 | en_US: y 29 | zh_Hans: y 30 | human_description: 31 | en_US: y 32 | zh_Hans: y 33 | llm_description: y 34 | form: llm 35 | extra: 36 | python: 37 | source: tools/add.py 38 | -------------------------------------------------------------------------------- /plugins/demo.public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIICCgKCAgEAvZw32uVbXyNWkaw/5YbIoK+YqHfZWK65SXf5Mm2w08O7/XCysej1 3 | UYi2pdi8ULtgiIuj4+rGcZuPPX23viW/QKo+inIw+02sWKAwA7si71TWTjJZnHg5 4 | wc6K9s3hiqK2oCve/vshraJnsDspZaGbry+aqbXs71hGSWM8JBbq4XY9dnItqAUN 5 | zmLRV3IDe4ZaeKwIFT3+jS7kYoEz5T8WWBi67ulj+pQ6vMUwJza5E0KZIQdZy7al 6 | sswWVBYvnwR0LZwZHDRIbqFW2uJDTGXHoh/NB6d7xO6kTb2jfAf4NwTtGiFJLBRF 7 | G6WBI3tAZTTnNY6bETZ3UBEaWHWAP/9a5BbY/qCDHOyg9EpTZ5E6vw7a5SCD9Tej 8 | GwoH7Qmt9xCetIeQZ/IerVnMP1CV45elLab383jtm8b8BqNZmfD5tMhWULkpti2X 9 | JY5Tg728ua5CeD3Rq7KCUXJgo7I0SjPxMm+yFA/EXBqtljEzF+D06uk6gLLasGdq 10 | 5ijpx9CndgXGfTbkW2So8M7wnZuD+oDEawK9qLYCrUHvglrsmBxYPOtcRVJY1SZ7 11 | k3U756XXLLRvMIQcPsDi/T5W5aTZ38H0IJRAoMt3RHj/XdT/CfgmMHz+LJbcLELf 12 | Y2YresPGD5pSl147YAk9Jebd8OdVROOItPANEglHfq9RQKzF2wDuXrECAwEAAQ== 13 | -----END RSA PUBLIC KEY----- 14 | -------------------------------------------------------------------------------- /plugins/mockgpt/models/llm/llm.yaml: -------------------------------------------------------------------------------- 1 | model: mock-gpt-v1 2 | label: 3 | zh_Hans: 模拟大模型 v1 4 | en_US: Mock GPT v1 5 | model_type: llm 6 | features: 7 | - multi-tool-call 8 | - agent-thought 9 | - stream-tool-call 10 | model_properties: 11 | mode: chat 12 | context_size: 16385 13 | parameter_rules: 14 | - name: temperature 15 | use_template: temperature 16 | - name: top_p 17 | use_template: top_p 18 | - name: presence_penalty 19 | use_template: presence_penalty 20 | - name: frequency_penalty 21 | use_template: frequency_penalty 22 | - name: max_tokens 23 | use_template: max_tokens 24 | default: 512 25 | min: 1 26 | max: 16385 27 | - name: response_format 28 | use_template: response_format 29 | pricing: 30 | input: '0.003' 31 | output: '0.004' 32 | unit: '0.001' 33 | currency: USD 34 | -------------------------------------------------------------------------------- /api/core/tools/builtin_tool/providers/calculator/tools/add.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Generator 2 | from typing import Any, Optional 3 | 4 | from core.helper.code_executor.code_executor import CodeExecutor, CodeLanguage 5 | from core.tools.builtin_tool.tool import BuiltinTool 6 | from core.tools.entities.tool_entities import ToolInvokeMessage 7 | from core.tools.errors import ToolInvokeError 8 | 9 | 10 | class Add(BuiltinTool): 11 | def _invoke( 12 | self, 13 | user_id: str, 14 | tool_parameters: dict[str, Any], 15 | conversation_id: Optional[str] = None, 16 | app_id: Optional[str] = None, 17 | message_id: Optional[str] = None, 18 | ) -> Generator[ToolInvokeMessage, None, None]: 19 | """ 20 | 加法运算 21 | """ 22 | 23 | x = tool_parameters.get("x", 0) 24 | y = tool_parameters.get("y", 0) 25 | 26 | result = str(x + y) 27 | yield self.create_text_message(result) 28 | -------------------------------------------------------------------------------- /plugins/mockgpt/provider/demo.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from collections.abc import Mapping 3 | 4 | from dify_plugin import ModelProvider 5 | from dify_plugin.entities.model import ModelType 6 | from dify_plugin.errors.model import CredentialsValidateFailedError 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | class DemoModelProvider(ModelProvider): 12 | def validate_provider_credentials(self, credentials: Mapping) -> None: 13 | """ 14 | Validate provider credentials 15 | if validate failed, raise exception 16 | 17 | :param credentials: provider credentials, credentials form defined in `provider_credential_schema`. 18 | """ 19 | try: 20 | pass 21 | except CredentialsValidateFailedError as ex: 22 | raise ex 23 | except Exception as ex: 24 | logger.exception( 25 | f"{self.get_provider_schema().provider} credentials validate failed" 26 | ) 27 | raise ex 28 | -------------------------------------------------------------------------------- /api/core/external_data_tool/weather_search/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": { 3 | "en-US": "Weather Search", 4 | "zh-Hans": "天气查询" 5 | }, 6 | "form_schema": [ 7 | { 8 | "type": "select", 9 | "label": { 10 | "en-US": "Temperature Unit", 11 | "zh-Hans": "温度单位" 12 | }, 13 | "variable": "temperature_unit", 14 | "required": true, 15 | "options": [ 16 | { 17 | "label": { 18 | "en-US": "Fahrenheit", 19 | "zh-Hans": "华氏度" 20 | }, 21 | "value": "fahrenheit" 22 | }, 23 | { 24 | "label": { 25 | "en-US": "Centigrade", 26 | "zh-Hans": "摄氏度" 27 | }, 28 | "value": "centigrade" 29 | } 30 | ], 31 | "default": "centigrade", 32 | "placeholder": "Please select temperature unit" 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /api/core/tools/builtin_tool/providers/calculator/_assets/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/core/external_data_tool/weather_search/weather_search.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from core.external_data_tool.base import ExternalDataTool 4 | 5 | 6 | class WeatherSearch(ExternalDataTool): 7 | """ 8 | The name of custom type must be unique, keep the same with directory and file name. 9 | """ 10 | name: str = "weather_search" 11 | 12 | @classmethod 13 | def validate_config(cls, tenant_id: str, config: dict) -> None: 14 | """ 15 | schema.json validation. It will be called when user save the config. 16 | 17 | Example: 18 | .. code-block:: python 19 | config = { 20 | "temperature_unit": "centigrade" 21 | } 22 | 23 | :param tenant_id: the id of workspace 24 | :param config: the variables of form config 25 | :return: 26 | """ 27 | 28 | if not config.get('temperature_unit'): 29 | raise ValueError('temperature unit is required') 30 | 31 | def query(self, inputs: dict, query: Optional[str] = None) -> str: 32 | """ 33 | Query the external data tool. 34 | 35 | :param inputs: user inputs 36 | :param query: the query of chat app 37 | :return: the tool query result 38 | """ 39 | city = inputs.get('city') 40 | temperature_unit = self.config.get('temperature_unit') 41 | 42 | if temperature_unit == 'fahrenheit': 43 | return f'Weather in {city} is 32°F' 44 | else: 45 | return f'Weather in {city} is 0°C' -------------------------------------------------------------------------------- /plugins/mockgpt/provider/demo.yaml: -------------------------------------------------------------------------------- 1 | provider: demo 2 | label: 3 | en_US: "Demo" 4 | description: 5 | en_US: "Models provided by demo." 6 | zh_Hans: "Demo 提供的模型。" 7 | icon_small: 8 | en_US: "icon.svg" # 保证 _assets 目录下存在 9 | icon_large: 10 | en_US: "icon.svg" # 保证 _assets 目录下存在 11 | background: "#E5E7EB" 12 | help: 13 | title: 14 | en_US: "Get your API Key from demo" 15 | zh_Hans: "从 Demo 获取 API Key" 16 | url: 17 | en_US: "https://__put_your_url_here__/account/api-keys" 18 | supported_model_types: 19 | - llm 20 | configurate_methods: 21 | - predefined-model 22 | - customizable-model 23 | model_credential_schema: 24 | model: 25 | label: 26 | en_US: Model Name 27 | zh_Hans: 模型名称 28 | placeholder: 29 | en_US: Enter your model name 30 | zh_Hans: 输入模型名称 31 | credential_form_schemas: 32 | - variable: openai_api_key 33 | label: 34 | en_US: API Key 35 | type: secret-input 36 | required: true 37 | placeholder: 38 | zh_Hans: 在此输入您的 API Key 39 | en_US: Enter your API Key 40 | provider_credential_schema: 41 | credential_form_schemas: 42 | - variable: openai_api_key 43 | label: 44 | en_US: API Key 45 | type: secret-input 46 | required: true 47 | placeholder: 48 | zh_Hans: 在此输入您的 API Key 49 | en_US: Enter your API Key 50 | models: 51 | llm: 52 | predefined: 53 | - "models/llm/*.yaml" 54 | extra: 55 | python: 56 | provider_source: provider/demo.py # 修改 57 | model_sources: 58 | - "models/llm/llm.py" 59 | -------------------------------------------------------------------------------- /api/core/moderation/cloud_service/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": { 3 | "en-US": "Cloud Service", 4 | "zh-Hans": "云服务" 5 | }, 6 | "form_schema": [ 7 | { 8 | "type": "select", 9 | "label": { 10 | "en-US": "Cloud Provider", 11 | "zh-Hans": "云厂商" 12 | }, 13 | "variable": "cloud_provider", 14 | "required": true, 15 | "options": [ 16 | { 17 | "label": { 18 | "en-US": "AWS", 19 | "zh-Hans": "亚马逊" 20 | }, 21 | "value": "AWS" 22 | }, 23 | { 24 | "label": { 25 | "en-US": "Google Cloud", 26 | "zh-Hans": "谷歌云" 27 | }, 28 | "value": "GoogleCloud" 29 | }, 30 | { 31 | "label": { 32 | "en-US": "Azure Cloud", 33 | "zh-Hans": "微软云" 34 | }, 35 | "value": "Azure" 36 | } 37 | ], 38 | "default": "GoogleCloud", 39 | "placeholder": "" 40 | }, 41 | { 42 | "type": "text-input", 43 | "label": { 44 | "en-US": "API Endpoint", 45 | "zh-Hans": "API Endpoint" 46 | }, 47 | "variable": "api_endpoint", 48 | "required": true, 49 | "max_length": 100, 50 | "default": "", 51 | "placeholder": "https://api.example.com" 52 | }, 53 | { 54 | "type": "paragraph", 55 | "label": { 56 | "en-US": "API Key", 57 | "zh-Hans": "API Key" 58 | }, 59 | "variable": "api_keys", 60 | "required": true, 61 | "default": "", 62 | "placeholder": "Paste your API key here" 63 | } 64 | ] 65 | } -------------------------------------------------------------------------------- /plugins/calculator/provider/calculator.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from dify_plugin import ToolProvider 4 | from dify_plugin.errors.tool import ToolProviderCredentialValidationError 5 | 6 | 7 | class CalculatorProvider(ToolProvider): 8 | 9 | def _validate_credentials(self, credentials: dict[str, Any]) -> None: 10 | try: 11 | """ 12 | IMPLEMENT YOUR VALIDATION HERE 13 | """ 14 | except Exception as e: 15 | raise ToolProviderCredentialValidationError(str(e)) 16 | 17 | ######################################################################################### 18 | # If OAuth is supported, uncomment the following functions. 19 | # Warning: please make sure that the sdk version is 0.4.2 or higher. 20 | ######################################################################################### 21 | # def _oauth_get_authorization_url(self, redirect_uri: str, system_credentials: Mapping[str, Any]) -> str: 22 | # """ 23 | # Generate the authorization URL for calculator OAuth. 24 | # """ 25 | # try: 26 | # """ 27 | # IMPLEMENT YOUR AUTHORIZATION URL GENERATION HERE 28 | # """ 29 | # except Exception as e: 30 | # raise ToolProviderOAuthError(str(e)) 31 | # return "" 32 | 33 | # def _oauth_get_credentials( 34 | # self, redirect_uri: str, system_credentials: Mapping[str, Any], request: Request 35 | # ) -> Mapping[str, Any]: 36 | # """ 37 | # Exchange code for access_token. 38 | # """ 39 | # try: 40 | # """ 41 | # IMPLEMENT YOUR CREDENTIALS EXCHANGE HERE 42 | # """ 43 | # except Exception as e: 44 | # raise ToolProviderOAuthError(str(e)) 45 | # return dict() 46 | 47 | # def _oauth_refresh_credentials( 48 | # self, redirect_uri: str, system_credentials: Mapping[str, Any], credentials: Mapping[str, Any] 49 | # ) -> OAuthCredentials: 50 | # """ 51 | # Refresh the credentials 52 | # """ 53 | # return OAuthCredentials(credentials=credentials, expires_at=-1) 54 | -------------------------------------------------------------------------------- /plugins/calculator/_assets/icon.svg: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /plugins/calculator/_assets/icon-dark.svg: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /plugins/demo.private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | 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 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /api/core/moderation/cloud_service/cloud_service.py: -------------------------------------------------------------------------------- 1 | from core.moderation.base import Moderation, ModerationAction, ModerationInputsResult, ModerationOutputsResult 2 | 3 | class CloudServiceModeration(Moderation): 4 | """ 5 | The name of custom type must be unique, keep the same with directory and file name. 6 | """ 7 | name: str = "cloud_service" 8 | 9 | @classmethod 10 | def validate_config(cls, tenant_id: str, config: dict) -> None: 11 | """ 12 | schema.json validation. It will be called when user save the config. 13 | 14 | Example: 15 | .. code-block:: python 16 | config = { 17 | "cloud_provider": "GoogleCloud", 18 | "api_endpoint": "https://api.example.com", 19 | "api_keys": "123456", 20 | "inputs_config": { 21 | "enabled": True, 22 | "preset_response": "Your content violates our usage policy. Please revise and try again." 23 | }, 24 | "outputs_config": { 25 | "enabled": True, 26 | "preset_response": "Your content violates our usage policy. Please revise and try again." 27 | } 28 | } 29 | 30 | :param tenant_id: the id of workspace 31 | :param config: the variables of form config 32 | :return: 33 | """ 34 | 35 | cls._validate_inputs_and_outputs_config(config, True) 36 | 37 | if not config.get("cloud_provider"): 38 | raise ValueError("cloud_provider is required") 39 | 40 | if not config.get("api_endpoint"): 41 | raise ValueError("api_endpoint is required") 42 | 43 | if not config.get("api_keys"): 44 | raise ValueError("api_keys is required") 45 | 46 | def moderation_for_inputs(self, inputs: dict, query: str = "") -> ModerationInputsResult: 47 | """ 48 | Moderation for inputs. 49 | 50 | :param inputs: user inputs 51 | :param query: the query of chat app, there is empty if is completion app 52 | :return: the moderation result 53 | """ 54 | flagged = False 55 | preset_response = "" 56 | 57 | if self.config['inputs_config']['enabled']: 58 | preset_response = self.config['inputs_config']['preset_response'] 59 | 60 | if query: 61 | inputs['query__'] = query 62 | flagged = self._is_violated(inputs) 63 | 64 | # return ModerationInputsResult(flagged=flagged, action=ModerationAction.overridden, inputs=inputs, query=query) 65 | return ModerationInputsResult(flagged=flagged, action=ModerationAction.DIRECT_OUTPUT, preset_response=preset_response) 66 | 67 | def moderation_for_outputs(self, text: str) -> ModerationOutputsResult: 68 | """ 69 | Moderation for outputs. 70 | 71 | :param text: the text of LLM response 72 | :return: the moderation result 73 | """ 74 | flagged = False 75 | preset_response = "" 76 | 77 | if self.config['outputs_config']['enabled']: 78 | preset_response = self.config['outputs_config']['preset_response'] 79 | 80 | flagged = self._is_violated({'text': text}) 81 | 82 | # return ModerationOutputsResult(flagged=flagged, action=ModerationAction.overridden, text=text) 83 | return ModerationOutputsResult(flagged=flagged, action=ModerationAction.DIRECT_OUTPUT, preset_response=preset_response) 84 | 85 | def _is_violated(self, inputs: dict): 86 | """ 87 | The main logic of moderation. 88 | 89 | :param inputs: 90 | :return: the moderation result 91 | """ 92 | return False -------------------------------------------------------------------------------- /.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 | 173 | # macOS 174 | .DS_Store 175 | .AppleDouble 176 | .LSOverride -------------------------------------------------------------------------------- /plugins/calculator/.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 | 173 | # macOS 174 | .DS_Store 175 | .AppleDouble 176 | .LSOverride -------------------------------------------------------------------------------- /plugins/mockgpt/.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 | 173 | # macOS 174 | .DS_Store 175 | .AppleDouble 176 | .LSOverride -------------------------------------------------------------------------------- /plugins/calculator/GUIDE.md: -------------------------------------------------------------------------------- 1 | # Dify Plugin Development Guide 2 | 3 | Welcome to Dify plugin development! This guide will help you get started quickly. 4 | 5 | ## Plugin Types 6 | 7 | Dify plugins extend three main capabilities: 8 | 9 | | Type | Description | Example | 10 | |------|-------------|---------| 11 | | **Tool** | Perform specific tasks | Google Search, Stable Diffusion | 12 | | **Model** | AI model integrations | OpenAI, Anthropic | 13 | | **Endpoint** | HTTP services | Custom APIs, integrations | 14 | 15 | You can create: 16 | - **Tool**: Tool provider with optional endpoints (e.g., Discord bot) 17 | - **Model**: Model provider only 18 | - **Extension**: Simple HTTP service 19 | 20 | ## Setup 21 | 22 | ### Requirements 23 | - Python 3.11+ 24 | - Dependencies: `pip install -r requirements.txt` 25 | 26 | ## Development Process 27 | 28 |
29 | 1. Manifest Structure 30 | 31 | Edit `manifest.yaml` to describe your plugin: 32 | 33 | ```yaml 34 | version: 0.1.0 # Required: Plugin version 35 | type: plugin # Required: plugin or bundle 36 | author: YourOrganization # Required: Organization name 37 | label: # Required: Multi-language names 38 | en_US: Plugin Name 39 | zh_Hans: 插件名称 40 | created_at: 2023-01-01T00:00:00Z # Required: Creation time (RFC3339) 41 | icon: assets/icon.png # Required: Icon path 42 | 43 | # Resources and permissions 44 | resource: 45 | memory: 268435456 # Max memory (bytes) 46 | permission: 47 | tool: 48 | enabled: true # Tool permission 49 | model: 50 | enabled: true # Model permission 51 | llm: true 52 | text_embedding: false 53 | # Other model types... 54 | # Other permissions... 55 | 56 | # Extensions definition 57 | plugins: 58 | tools: 59 | - tools/my_tool.yaml # Tool definition files 60 | models: 61 | - models/my_model.yaml # Model definition files 62 | endpoints: 63 | - endpoints/my_api.yaml # Endpoint definition files 64 | 65 | # Runtime metadata 66 | meta: 67 | version: 0.0.1 # Manifest format version 68 | arch: 69 | - amd64 70 | - arm64 71 | runner: 72 | language: python 73 | version: "3.12" 74 | entrypoint: main 75 | ``` 76 | 77 | **Restrictions:** 78 | - Cannot extend both tools and models 79 | - Must have at least one extension 80 | - Cannot extend both models and endpoints 81 | - Limited to one supplier per extension type 82 |
83 | 84 |
85 | 2. Implementation Examples 86 | 87 | Study these examples to understand plugin implementation: 88 | 89 | - [OpenAI](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/openai) - Model provider 90 | - [Google Search](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/google) - Tool provider 91 | - [Neko](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko) - Endpoint group 92 |
93 | 94 |
95 | 3. Testing & Debugging 96 | 97 | 1. Copy `.env.example` to `.env` and configure: 98 | ``` 99 | INSTALL_METHOD=remote 100 | REMOTE_INSTALL_URL=debug.dify.ai:5003 101 | REMOTE_INSTALL_KEY=your-debug-key 102 | ``` 103 | 104 | 2. Run your plugin: 105 | ```bash 106 | python -m main 107 | ``` 108 | 109 | 3. Refresh your Dify instance to see the plugin (marked as "debugging") 110 |
111 | 112 |
113 | 4. Publishing 114 | 115 | #### Manual Packaging 116 | ```bash 117 | dify-plugin plugin package ./YOUR_PLUGIN_DIR 118 | ``` 119 | 120 | #### Automated GitHub Workflow 121 | 122 | Configure GitHub Actions to automate PR creation: 123 | 124 | 1. Create a Personal Access Token for your forked repository 125 | 2. Add it as `PLUGIN_ACTION` secret in your source repo 126 | 3. Create `.github/workflows/plugin-publish.yml` 127 | 128 | When you create a release, the action will: 129 | - Package your plugin 130 | - Create a PR to your fork 131 | 132 | [Detailed workflow documentation](https://docs.dify.ai/plugins/publish-plugins/plugin-auto-publish-pr) 133 |
134 | 135 | ## Privacy Policy 136 | 137 | If publishing to the Marketplace, provide a privacy policy in [PRIVACY.md](PRIVACY.md). -------------------------------------------------------------------------------- /plugins/mockgpt/GUIDE.md: -------------------------------------------------------------------------------- 1 | # Dify Plugin Development Guide 2 | 3 | Welcome to Dify plugin development! This guide will help you get started quickly. 4 | 5 | ## Plugin Types 6 | 7 | Dify plugins extend three main capabilities: 8 | 9 | | Type | Description | Example | 10 | |------|-------------|---------| 11 | | **Tool** | Perform specific tasks | Google Search, Stable Diffusion | 12 | | **Model** | AI model integrations | OpenAI, Anthropic | 13 | | **Endpoint** | HTTP services | Custom APIs, integrations | 14 | 15 | You can create: 16 | - **Tool**: Tool provider with optional endpoints (e.g., Discord bot) 17 | - **Model**: Model provider only 18 | - **Extension**: Simple HTTP service 19 | 20 | ## Setup 21 | 22 | ### Requirements 23 | - Python 3.11+ 24 | - Dependencies: `pip install -r requirements.txt` 25 | 26 | ## Development Process 27 | 28 |
29 | 1. Manifest Structure 30 | 31 | Edit `manifest.yaml` to describe your plugin: 32 | 33 | ```yaml 34 | version: 0.1.0 # Required: Plugin version 35 | type: plugin # Required: plugin or bundle 36 | author: YourOrganization # Required: Organization name 37 | label: # Required: Multi-language names 38 | en_US: Plugin Name 39 | zh_Hans: 插件名称 40 | created_at: 2023-01-01T00:00:00Z # Required: Creation time (RFC3339) 41 | icon: assets/icon.png # Required: Icon path 42 | 43 | # Resources and permissions 44 | resource: 45 | memory: 268435456 # Max memory (bytes) 46 | permission: 47 | tool: 48 | enabled: true # Tool permission 49 | model: 50 | enabled: true # Model permission 51 | llm: true 52 | text_embedding: false 53 | # Other model types... 54 | # Other permissions... 55 | 56 | # Extensions definition 57 | plugins: 58 | tools: 59 | - tools/my_tool.yaml # Tool definition files 60 | models: 61 | - models/my_model.yaml # Model definition files 62 | endpoints: 63 | - endpoints/my_api.yaml # Endpoint definition files 64 | 65 | # Runtime metadata 66 | meta: 67 | version: 0.0.1 # Manifest format version 68 | arch: 69 | - amd64 70 | - arm64 71 | runner: 72 | language: python 73 | version: "3.12" 74 | entrypoint: main 75 | ``` 76 | 77 | **Restrictions:** 78 | - Cannot extend both tools and models 79 | - Must have at least one extension 80 | - Cannot extend both models and endpoints 81 | - Limited to one supplier per extension type 82 |
83 | 84 |
85 | 2. Implementation Examples 86 | 87 | Study these examples to understand plugin implementation: 88 | 89 | - [OpenAI](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/openai) - Model provider 90 | - [Google Search](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/google) - Tool provider 91 | - [Neko](https://github.com/langgenius/dify-plugin-sdks/tree/main/python/examples/neko) - Endpoint group 92 |
93 | 94 |
95 | 3. Testing & Debugging 96 | 97 | 1. Copy `.env.example` to `.env` and configure: 98 | ``` 99 | INSTALL_METHOD=remote 100 | REMOTE_INSTALL_URL=debug.dify.ai:5003 101 | REMOTE_INSTALL_KEY=your-debug-key 102 | ``` 103 | 104 | 2. Run your plugin: 105 | ```bash 106 | python -m main 107 | ``` 108 | 109 | 3. Refresh your Dify instance to see the plugin (marked as "debugging") 110 |
111 | 112 |
113 | 4. Publishing 114 | 115 | #### Manual Packaging 116 | ```bash 117 | dify-plugin plugin package ./YOUR_PLUGIN_DIR 118 | ``` 119 | 120 | #### Automated GitHub Workflow 121 | 122 | Configure GitHub Actions to automate PR creation: 123 | 124 | 1. Create a Personal Access Token for your forked repository 125 | 2. Add it as `PLUGIN_ACTION` secret in your source repo 126 | 3. Create `.github/workflows/plugin-publish.yml` 127 | 128 | When you create a release, the action will: 129 | - Package your plugin 130 | - Create a PR to your fork 131 | 132 | [Detailed workflow documentation](https://docs.dify.ai/plugins/publish-plugins/plugin-auto-publish-pr) 133 |
134 | 135 | ## Privacy Policy 136 | 137 | If publishing to the Marketplace, provide a privacy policy in [PRIVACY.md](PRIVACY.md). -------------------------------------------------------------------------------- /plugins/mockgpt/_assets/icon.svg: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /plugins/mockgpt/_assets/icon-dark.svg: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /plugins/mockgpt/.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 | .github/ 174 | 175 | # Mac 176 | .DS_Store 177 | 178 | # Windows 179 | Thumbs.db 180 | 181 | # Dify plugin packages 182 | # To prevent packaging repetitively 183 | *.difypkg 184 | 185 | -------------------------------------------------------------------------------- /plugins/calculator/.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 | .github/ 174 | 175 | # Mac 176 | .DS_Store 177 | 178 | # Windows 179 | Thumbs.db 180 | 181 | # Dify plugin packages 182 | # To prevent packaging repetitively 183 | *.difypkg 184 | 185 | -------------------------------------------------------------------------------- /plugins/calculator/.github/workflows/plugin-publish.yml: -------------------------------------------------------------------------------- 1 | name: Plugin Publish Workflow 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v3 13 | 14 | - name: Download CLI tool 15 | run: | 16 | mkdir -p $RUNNER_TEMP/bin 17 | cd $RUNNER_TEMP/bin 18 | 19 | wget https://github.com/langgenius/dify-plugin-daemon/releases/download/0.0.6/dify-plugin-linux-amd64 20 | chmod +x dify-plugin-linux-amd64 21 | 22 | echo "CLI tool location:" 23 | pwd 24 | ls -la dify-plugin-linux-amd64 25 | 26 | - name: Get basic info from manifest 27 | id: get_basic_info 28 | run: | 29 | PLUGIN_NAME=$(grep "^name:" manifest.yaml | cut -d' ' -f2) 30 | echo "Plugin name: $PLUGIN_NAME" 31 | echo "plugin_name=$PLUGIN_NAME" >> $GITHUB_OUTPUT 32 | 33 | VERSION=$(grep "^version:" manifest.yaml | cut -d' ' -f2) 34 | echo "Plugin version: $VERSION" 35 | echo "version=$VERSION" >> $GITHUB_OUTPUT 36 | 37 | # If the author's name is not your github username, you can change the author here 38 | AUTHOR=$(grep "^author:" manifest.yaml | cut -d' ' -f2) 39 | echo "Plugin author: $AUTHOR" 40 | echo "author=$AUTHOR" >> $GITHUB_OUTPUT 41 | 42 | - name: Package Plugin 43 | id: package 44 | run: | 45 | cd $GITHUB_WORKSPACE 46 | PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg" 47 | $RUNNER_TEMP/bin/dify-plugin-linux-amd64 plugin package . -o "$PACKAGE_NAME" 48 | 49 | echo "Package result:" 50 | ls -la "$PACKAGE_NAME" 51 | echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT 52 | 53 | echo "\nFull file path:" 54 | pwd 55 | echo "\nDirectory structure:" 56 | tree || ls -R 57 | 58 | - name: Checkout target repo 59 | uses: actions/checkout@v3 60 | with: 61 | repository: ${{steps.get_basic_info.outputs.author}}/dify-plugins 62 | path: dify-plugins 63 | token: ${{ secrets.PLUGIN_ACTION }} 64 | fetch-depth: 1 65 | persist-credentials: true 66 | 67 | - name: Prepare and create PR 68 | run: | 69 | PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg" 70 | mkdir -p dify-plugins/${{ steps.get_basic_info.outputs.author }}/${{ steps.get_basic_info.outputs.plugin_name }} 71 | mv "$PACKAGE_NAME" dify-plugins/${{ steps.get_basic_info.outputs.author }}/${{ steps.get_basic_info.outputs.plugin_name }}/ 72 | 73 | cd dify-plugins 74 | 75 | git config user.name "GitHub Actions" 76 | git config user.email "actions@github.com" 77 | 78 | git fetch origin main 79 | git checkout main 80 | git pull origin main 81 | 82 | BRANCH_NAME="bump-${{ steps.get_basic_info.outputs.plugin_name }}-plugin-${{ steps.get_basic_info.outputs.version }}" 83 | git checkout -b "$BRANCH_NAME" 84 | 85 | git add . 86 | git commit -m "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin to version ${{ steps.get_basic_info.outputs.version }}" 87 | 88 | git push -u origin "$BRANCH_NAME" --force 89 | 90 | git branch -a 91 | echo "Waiting for branch to sync..." 92 | sleep 10 # Wait 10 seconds for branch sync 93 | 94 | - name: Create PR via GitHub API 95 | env: 96 | # How to config the token: 97 | # 1. Profile -> Settings -> Developer settings -> Personal access tokens -> Generate new token (with repo scope) -> Copy the token 98 | # 2. Go to the target repository -> Settings -> Secrets and variables -> Actions -> New repository secret -> Add the token as PLUGIN_ACTION 99 | GH_TOKEN: ${{ secrets.PLUGIN_ACTION }} 100 | run: | 101 | gh pr create \ 102 | --repo langgenius/dify-plugins \ 103 | --head "${{ steps.get_basic_info.outputs.author }}:${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}" \ 104 | --base main \ 105 | --title "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin to version ${{ steps.get_basic_info.outputs.version }}" \ 106 | --body "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin package to version ${{ steps.get_basic_info.outputs.version }} 107 | 108 | Changes: 109 | - Updated plugin package file" || echo "PR already exists or creation skipped." # Handle cases where PR already exists 110 | -------------------------------------------------------------------------------- /plugins/mockgpt/.github/workflows/plugin-publish.yml: -------------------------------------------------------------------------------- 1 | name: Plugin Publish Workflow 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | publish: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout code 12 | uses: actions/checkout@v3 13 | 14 | - name: Download CLI tool 15 | run: | 16 | mkdir -p $RUNNER_TEMP/bin 17 | cd $RUNNER_TEMP/bin 18 | 19 | wget https://github.com/langgenius/dify-plugin-daemon/releases/download/0.0.6/dify-plugin-linux-amd64 20 | chmod +x dify-plugin-linux-amd64 21 | 22 | echo "CLI tool location:" 23 | pwd 24 | ls -la dify-plugin-linux-amd64 25 | 26 | - name: Get basic info from manifest 27 | id: get_basic_info 28 | run: | 29 | PLUGIN_NAME=$(grep "^name:" manifest.yaml | cut -d' ' -f2) 30 | echo "Plugin name: $PLUGIN_NAME" 31 | echo "plugin_name=$PLUGIN_NAME" >> $GITHUB_OUTPUT 32 | 33 | VERSION=$(grep "^version:" manifest.yaml | cut -d' ' -f2) 34 | echo "Plugin version: $VERSION" 35 | echo "version=$VERSION" >> $GITHUB_OUTPUT 36 | 37 | # If the author's name is not your github username, you can change the author here 38 | AUTHOR=$(grep "^author:" manifest.yaml | cut -d' ' -f2) 39 | echo "Plugin author: $AUTHOR" 40 | echo "author=$AUTHOR" >> $GITHUB_OUTPUT 41 | 42 | - name: Package Plugin 43 | id: package 44 | run: | 45 | cd $GITHUB_WORKSPACE 46 | PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg" 47 | $RUNNER_TEMP/bin/dify-plugin-linux-amd64 plugin package . -o "$PACKAGE_NAME" 48 | 49 | echo "Package result:" 50 | ls -la "$PACKAGE_NAME" 51 | echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT 52 | 53 | echo "\nFull file path:" 54 | pwd 55 | echo "\nDirectory structure:" 56 | tree || ls -R 57 | 58 | - name: Checkout target repo 59 | uses: actions/checkout@v3 60 | with: 61 | repository: ${{steps.get_basic_info.outputs.author}}/dify-plugins 62 | path: dify-plugins 63 | token: ${{ secrets.PLUGIN_ACTION }} 64 | fetch-depth: 1 65 | persist-credentials: true 66 | 67 | - name: Prepare and create PR 68 | run: | 69 | PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg" 70 | mkdir -p dify-plugins/${{ steps.get_basic_info.outputs.author }}/${{ steps.get_basic_info.outputs.plugin_name }} 71 | mv "$PACKAGE_NAME" dify-plugins/${{ steps.get_basic_info.outputs.author }}/${{ steps.get_basic_info.outputs.plugin_name }}/ 72 | 73 | cd dify-plugins 74 | 75 | git config user.name "GitHub Actions" 76 | git config user.email "actions@github.com" 77 | 78 | git fetch origin main 79 | git checkout main 80 | git pull origin main 81 | 82 | BRANCH_NAME="bump-${{ steps.get_basic_info.outputs.plugin_name }}-plugin-${{ steps.get_basic_info.outputs.version }}" 83 | git checkout -b "$BRANCH_NAME" 84 | 85 | git add . 86 | git commit -m "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin to version ${{ steps.get_basic_info.outputs.version }}" 87 | 88 | git push -u origin "$BRANCH_NAME" --force 89 | 90 | git branch -a 91 | echo "Waiting for branch to sync..." 92 | sleep 10 # Wait 10 seconds for branch sync 93 | 94 | - name: Create PR via GitHub API 95 | env: 96 | # How to config the token: 97 | # 1. Profile -> Settings -> Developer settings -> Personal access tokens -> Generate new token (with repo scope) -> Copy the token 98 | # 2. Go to the target repository -> Settings -> Secrets and variables -> Actions -> New repository secret -> Add the token as PLUGIN_ACTION 99 | GH_TOKEN: ${{ secrets.PLUGIN_ACTION }} 100 | run: | 101 | gh pr create \ 102 | --repo langgenius/dify-plugins \ 103 | --head "${{ steps.get_basic_info.outputs.author }}:${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}" \ 104 | --base main \ 105 | --title "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin to version ${{ steps.get_basic_info.outputs.version }}" \ 106 | --body "bump ${{ steps.get_basic_info.outputs.plugin_name }} plugin package to version ${{ steps.get_basic_info.outputs.version }} 107 | 108 | Changes: 109 | - Updated plugin package file" || echo "PR already exists or creation skipped." # Handle cases where PR already exists 110 | -------------------------------------------------------------------------------- /plugins/mockgpt/models/llm/llm.py: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | import logging 4 | from collections.abc import Generator 5 | from typing import Optional, Union, List 6 | 7 | from dify_plugin import LargeLanguageModel 8 | from dify_plugin.entities import I18nObject 9 | from dify_plugin.errors.model import CredentialsValidateFailedError, InvokeError 10 | from dify_plugin.entities.model import AIModelEntity, FetchFrom, ModelType 11 | from dify_plugin.entities.model.llm import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage 12 | from dify_plugin.entities.model.message import PromptMessage, PromptMessageTool, AssistantPromptMessage 13 | 14 | logger = logging.getLogger(__name__) 15 | 16 | class MockGptLargeLanguageModel(LargeLanguageModel): 17 | """ 18 | MockGPT 实现 19 | """ 20 | 21 | def _invoke( 22 | self, 23 | model: str, 24 | credentials: dict, 25 | prompt_messages: list[PromptMessage], 26 | model_parameters: dict, 27 | tools: Optional[list[PromptMessageTool]] = None, 28 | stop: Optional[list[str]] = None, 29 | stream: bool = True, 30 | user: Optional[str] = None, 31 | ) -> Union[LLMResult, Generator]: 32 | """ 33 | 调用大语言模型 34 | """ 35 | 36 | # 模拟响应内容 37 | demo_responses = [ 38 | "这是一个演示模型的回复。我可以帮助您了解 Dify 插件的工作原理。", 39 | "作为演示模型,我会生成模拟的响应内容来展示插件功能。", 40 | "您好!这是 Demo AI 模型的模拟输出,用于演示插件开发流程。" 41 | ] 42 | 43 | response_text = random.choice(demo_responses) 44 | 45 | if stream: 46 | return self._handle_stream_response(model, prompt_messages, response_text) 47 | else: 48 | return self._handle_sync_response(model, prompt_messages, response_text) 49 | 50 | def _handle_stream_response(self, model: str, prompt_messages: List[PromptMessage], 51 | response_text: str) -> Generator: 52 | """ 53 | 处理流式响应 54 | """ 55 | # 模拟流式输出 56 | words = response_text.split() 57 | for i, word in enumerate(words): 58 | chunk_text = word + (" " if i < len(words) - 1 else "") 59 | 60 | delta = LLMResultChunkDelta( 61 | index=0, 62 | message=AssistantPromptMessage(content=chunk_text), 63 | finish_reason=None if i < len(words) - 1 else "stop", 64 | usage=self._calc_usage(response_text) if i == len(words) - 1 else None 65 | ) 66 | 67 | yield LLMResultChunk( 68 | model=model, 69 | prompt_messages=prompt_messages, 70 | system_fingerprint=None, 71 | delta=delta 72 | ) 73 | 74 | # 模拟网络延迟 75 | time.sleep(0.1) 76 | 77 | def _handle_sync_response(self, model: str, prompt_messages: List[PromptMessage], 78 | response_text: str) -> LLMResult: 79 | """ 80 | 处理同步响应 81 | """ 82 | return LLMResult( 83 | model=model, 84 | prompt_messages=prompt_messages, 85 | message=AssistantPromptMessage(content=response_text), 86 | usage=self._calc_usage(response_text), 87 | system_fingerprint=None 88 | ) 89 | 90 | def _calc_usage(self, text: str) -> LLMUsage: 91 | """ 92 | 计算使用量(模拟) 93 | """ 94 | prompt_tokens = 50 # 模拟 95 | completion_tokens = len(text.split()) 96 | 97 | return LLMUsage( 98 | prompt_tokens=prompt_tokens, 99 | prompt_unit_price=0.001, 100 | prompt_price_unit=1000, 101 | prompt_price=0.00005, 102 | completion_tokens=completion_tokens, 103 | completion_unit_price=0.002, 104 | completion_price_unit=1000, 105 | completion_price=completion_tokens * 0.000002, 106 | total_tokens=prompt_tokens + completion_tokens, 107 | total_price=0.00005 + completion_tokens * 0.000002, 108 | currency="USD", 109 | latency=1.5 110 | ) 111 | 112 | def get_num_tokens( 113 | self, 114 | model: str, 115 | credentials: dict, 116 | prompt_messages: list[PromptMessage], 117 | tools: Optional[list[PromptMessageTool]] = None, 118 | ) -> int: 119 | """ 120 | 计算 token 数量(模拟) 121 | """ 122 | total_text = "" 123 | for message in prompt_messages: 124 | if isinstance(message.content, str): 125 | total_text += message.content 126 | 127 | # 简单估算:中文字符算1个token,英文单词算1个token 128 | return len(total_text.split()) + len([c for c in total_text if '\u4e00' <= c <= '\u9fff']) 129 | 130 | def validate_credentials(self, model: str, credentials: dict) -> None: 131 | """ 132 | 验证模型凭据 133 | """ 134 | try: 135 | pass 136 | except Exception as ex: 137 | raise CredentialsValidateFailedError(str(ex)) 138 | 139 | def get_customizable_model_schema( 140 | self, model: str, credentials: dict 141 | ) -> AIModelEntity: 142 | """ 143 | 返回模型 Schema 144 | """ 145 | entity = AIModelEntity( 146 | model=model, 147 | label=I18nObject(zh_Hans=model, en_US=model), 148 | model_type=ModelType.LLM, 149 | features=[], 150 | fetch_from=FetchFrom.CUSTOMIZABLE_MODEL, 151 | model_properties={}, 152 | parameter_rules=[], 153 | ) 154 | 155 | return entity 156 | 157 | @property 158 | def _invoke_error_mapping(self) -> dict: 159 | """ 160 | 错误映射 161 | """ 162 | return { 163 | InvokeError: [Exception] 164 | } --------------------------------------------------------------------------------