From d2ff8a2381b044a31f06d3b7aa410bf9fd860ce7 Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Mon, 6 Jan 2025 14:59:40 +0800 Subject: [PATCH 1/6] fix: bugs --- api/commands.py | 2 +- api/controllers/inner_api/plugin/plugin.py | 109 ++++++++++++--------- 2 files changed, 62 insertions(+), 49 deletions(-) diff --git a/api/commands.py b/api/commands.py index 1b1abcd9c3..9146075cf2 100644 --- a/api/commands.py +++ b/api/commands.py @@ -695,7 +695,7 @@ def extract_unique_plugins(output_file: str, input_file: str): """ click.echo(click.style("Starting extract unique plugins.", fg="white")) - PluginMigration.extract_unique_plugins(input_file, output_file) + PluginMigration.extract_unique_plugins_to_file(input_file, output_file) click.echo(click.style("Extract unique plugins completed.", fg="green")) diff --git a/api/controllers/inner_api/plugin/plugin.py b/api/controllers/inner_api/plugin/plugin.py index d147404517..f3a9a45c54 100644 --- a/api/controllers/inner_api/plugin/plugin.py +++ b/api/controllers/inner_api/plugin/plugin.py @@ -5,6 +5,7 @@ from controllers.inner_api import api from controllers.inner_api.plugin.wraps import get_user_tenant, plugin_data from controllers.inner_api.wraps import plugin_inner_api_only from core.file.helpers import get_signed_file_url_for_plugin +from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.backwards_invocation.app import PluginAppBackwardsInvocation from core.plugin.backwards_invocation.base import BaseBackwardsInvocationResponse from core.plugin.backwards_invocation.encrypt import PluginEncrypter @@ -52,15 +53,17 @@ class PluginInvokeTextEmbeddingApi(Resource): @plugin_data(payload_type=RequestInvokeTextEmbedding) def post(self, user_model: Account | EndUser, tenant_model: Tenant, payload: RequestInvokeTextEmbedding): try: - return BaseBackwardsInvocationResponse( - data=PluginModelBackwardsInvocation.invoke_text_embedding( - user_id=user_model.id, - tenant=tenant_model, - payload=payload, + return jsonable_encoder( + BaseBackwardsInvocationResponse( + data=PluginModelBackwardsInvocation.invoke_text_embedding( + user_id=user_model.id, + tenant=tenant_model, + payload=payload, + ) ) - ).model_dump() + ) except Exception as e: - return BaseBackwardsInvocationResponse(error=str(e)).model_dump() + return jsonable_encoder(BaseBackwardsInvocationResponse(error=str(e))) class PluginInvokeRerankApi(Resource): @@ -70,15 +73,17 @@ class PluginInvokeRerankApi(Resource): @plugin_data(payload_type=RequestInvokeRerank) def post(self, user_model: Account | EndUser, tenant_model: Tenant, payload: RequestInvokeRerank): try: - return BaseBackwardsInvocationResponse( - data=PluginModelBackwardsInvocation.invoke_rerank( - user_id=user_model.id, - tenant=tenant_model, - payload=payload, + return jsonable_encoder( + BaseBackwardsInvocationResponse( + data=PluginModelBackwardsInvocation.invoke_rerank( + user_id=user_model.id, + tenant=tenant_model, + payload=payload, + ) ) - ).model_dump() + ) except Exception as e: - return BaseBackwardsInvocationResponse(error=str(e)).model_dump() + return jsonable_encoder(BaseBackwardsInvocationResponse(error=str(e))) class PluginInvokeTTSApi(Resource): @@ -105,15 +110,17 @@ class PluginInvokeSpeech2TextApi(Resource): @plugin_data(payload_type=RequestInvokeSpeech2Text) def post(self, user_model: Account | EndUser, tenant_model: Tenant, payload: RequestInvokeSpeech2Text): try: - return BaseBackwardsInvocationResponse( - data=PluginModelBackwardsInvocation.invoke_speech2text( - user_id=user_model.id, - tenant=tenant_model, - payload=payload, + return jsonable_encoder( + BaseBackwardsInvocationResponse( + data=PluginModelBackwardsInvocation.invoke_speech2text( + user_id=user_model.id, + tenant=tenant_model, + payload=payload, + ) ) - ).model_dump() + ) except Exception as e: - return BaseBackwardsInvocationResponse(error=str(e)).model_dump() + return jsonable_encoder(BaseBackwardsInvocationResponse(error=str(e))) class PluginInvokeModerationApi(Resource): @@ -123,15 +130,17 @@ class PluginInvokeModerationApi(Resource): @plugin_data(payload_type=RequestInvokeModeration) def post(self, user_model: Account | EndUser, tenant_model: Tenant, payload: RequestInvokeModeration): try: - return BaseBackwardsInvocationResponse( - data=PluginModelBackwardsInvocation.invoke_moderation( - user_id=user_model.id, - tenant=tenant_model, - payload=payload, + return jsonable_encoder( + BaseBackwardsInvocationResponse( + data=PluginModelBackwardsInvocation.invoke_moderation( + user_id=user_model.id, + tenant=tenant_model, + payload=payload, + ) ) - ).model_dump() + ) except Exception as e: - return BaseBackwardsInvocationResponse(error=str(e)).model_dump() + return jsonable_encoder(BaseBackwardsInvocationResponse(error=str(e))) class PluginInvokeToolApi(Resource): @@ -162,18 +171,20 @@ class PluginInvokeParameterExtractorNodeApi(Resource): @plugin_data(payload_type=RequestInvokeParameterExtractorNode) def post(self, user_model: Account | EndUser, tenant_model: Tenant, payload: RequestInvokeParameterExtractorNode): try: - return BaseBackwardsInvocationResponse( - data=PluginNodeBackwardsInvocation.invoke_parameter_extractor( - tenant_id=tenant_model.id, - user_id=user_model.id, - parameters=payload.parameters, - model_config=payload.model, - instruction=payload.instruction, - query=payload.query, + return jsonable_encoder( + BaseBackwardsInvocationResponse( + data=PluginNodeBackwardsInvocation.invoke_parameter_extractor( + tenant_id=tenant_model.id, + user_id=user_model.id, + parameters=payload.parameters, + model_config=payload.model, + instruction=payload.instruction, + query=payload.query, + ) ) - ).model_dump() + ) except Exception as e: - return BaseBackwardsInvocationResponse(error=str(e)).model_dump() + return jsonable_encoder(BaseBackwardsInvocationResponse(error=str(e))) class PluginInvokeQuestionClassifierNodeApi(Resource): @@ -183,18 +194,20 @@ class PluginInvokeQuestionClassifierNodeApi(Resource): @plugin_data(payload_type=RequestInvokeQuestionClassifierNode) def post(self, user_model: Account | EndUser, tenant_model: Tenant, payload: RequestInvokeQuestionClassifierNode): try: - return BaseBackwardsInvocationResponse( - data=PluginNodeBackwardsInvocation.invoke_question_classifier( - tenant_id=tenant_model.id, - user_id=user_model.id, - query=payload.query, - model_config=payload.model, - classes=payload.classes, - instruction=payload.instruction, + return jsonable_encoder( + BaseBackwardsInvocationResponse( + data=PluginNodeBackwardsInvocation.invoke_question_classifier( + tenant_id=tenant_model.id, + user_id=user_model.id, + query=payload.query, + model_config=payload.model, + classes=payload.classes, + instruction=payload.instruction, + ) ) - ).model_dump() + ) except Exception as e: - return BaseBackwardsInvocationResponse(error=str(e)).model_dump() + return jsonable_encoder(BaseBackwardsInvocationResponse(error=str(e))) class PluginInvokeAppApi(Resource): From 3799d409379eca6796ea6f48072b3e7d37ed2e35 Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Mon, 6 Jan 2025 20:28:50 +0800 Subject: [PATCH 2/6] feat: support docker deployment for plugin --- .gitignore | 1 + api/.env.example | 2 +- api/configs/feature/__init__.py | 2 +- api/core/plugin/manager/base.py | 2 +- api/tests/integration_tests/.env.example | 2 +- docker/.env.example | 24 +++++++++ docker/docker-compose-template.yaml | 50 +++++++++++++++-- docker/docker-compose.middleware.yaml | 30 +++++++++++ docker/docker-compose.yaml | 66 +++++++++++++++++++++-- docker/middleware.env.example | 26 +++++++++ docker/nginx/conf.d/default.conf.template | 5 ++ 11 files changed, 200 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 1423bfee56..ca95df4515 100644 --- a/.gitignore +++ b/.gitignore @@ -175,6 +175,7 @@ docker/volumes/pgvector/data/* docker/volumes/pgvecto_rs/data/* docker/volumes/couchbase/* docker/volumes/oceanbase/* +docker/volumes/plugin_daemon/* !docker/volumes/oceanbase/init.d docker/nginx/conf.d/default.conf diff --git a/api/.env.example b/api/.env.example index 5a13ac69de..4d1358fa69 100644 --- a/api/.env.example +++ b/api/.env.example @@ -420,7 +420,7 @@ POSITION_PROVIDER_EXCLUDES= # Plugin configuration PLUGIN_API_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1 -PLUGIN_API_URL=http://127.0.0.1:5002 +PLUGIN_DAEMON_URL=http://127.0.0.1:5002 PLUGIN_REMOTE_INSTALL_PORT=5003 PLUGIN_REMOTE_INSTALL_HOST=localhost PLUGIN_MAX_PACKAGE_SIZE=15728640 diff --git a/api/configs/feature/__init__.py b/api/configs/feature/__init__.py index dcfebd0a4e..7a8b2dc6f8 100644 --- a/api/configs/feature/__init__.py +++ b/api/configs/feature/__init__.py @@ -139,7 +139,7 @@ class PluginConfig(BaseSettings): Plugin configs """ - PLUGIN_API_URL: HttpUrl = Field( + PLUGIN_DAEMON_URL: HttpUrl = Field( description="Plugin API URL", default="http://plugin:5002", ) diff --git a/api/core/plugin/manager/base.py b/api/core/plugin/manager/base.py index 60a54b34cf..9941ec97d4 100644 --- a/api/core/plugin/manager/base.py +++ b/api/core/plugin/manager/base.py @@ -29,7 +29,7 @@ from core.plugin.manager.exc import ( PluginUniqueIdentifierError, ) -plugin_daemon_inner_api_baseurl = dify_config.PLUGIN_API_URL +plugin_daemon_inner_api_baseurl = dify_config.PLUGIN_DAEMON_URL plugin_daemon_inner_api_key = dify_config.PLUGIN_API_KEY T = TypeVar("T", bound=(BaseModel | dict | list | bool | str)) diff --git a/api/tests/integration_tests/.env.example b/api/tests/integration_tests/.env.example index 95cca83b44..5caa982b88 100644 --- a/api/tests/integration_tests/.env.example +++ b/api/tests/integration_tests/.env.example @@ -86,7 +86,7 @@ ZHINAO_API_KEY= # Plugin configuration PLUGIN_API_KEY= -PLUGIN_API_URL= +PLUGIN_DAEMON_URL= INNER_API_KEY= # Marketplace configuration diff --git a/docker/.env.example b/docker/.env.example index 50ba856bd3..f911b48dd8 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -923,3 +923,27 @@ CREATE_TIDB_SERVICE_JOB_ENABLED=false # Maximum number of submitted thread count in a ThreadPool for parallel node execution MAX_SUBMIT_COUNT=100 +# ------------------------------ +# Plugin Daemon Configuration +# ------------------------------ + +DB_PLUGIN_DATABASE=dify-plugin +EXPOSE_PLUGIN_DAEMON_PORT=5002 +PLUGIN_DAEMON_PORT=5002 +PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi +PLUGIN_DAEMON_URL=http://plugin_daemon:5002 +PLUGIN_MAX_PACKAGE_SIZE=52428800 +PLUGIN_PPROF_ENABLED=false + +PLUGIN_DEBUGGING_HOST=0.0.0.0 +PLUGIN_DEBUGGING_PORT=5003 +EXPOSE_PLUGIN_DEBUGGING_HOST=localhost +EXPOSE_PLUGIN_DEBUGGING_PORT=5003 + +PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1 +PLUGIN_DIFY_INNER_API_URL=http://api:5001 + +ENDPOINT_URL_TEMPLATE=http://localhost/e/{hook_id} + +MARKETPLACE_ENABLED=true +MARKETPLACE_API_URL=https://marketplace-plugin.dify.dev diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index d4e0ba49d0..8426e1bcdc 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -2,7 +2,7 @@ x-shared-env: &shared-api-worker-env services: # API service api: - image: langgenius/dify-api:0.14.2 + image: langgenius/dify-api:dev-plugin-deploy restart: always environment: # Use the shared environment variables. @@ -12,6 +12,15 @@ services: SENTRY_DSN: ${API_SENTRY_DSN:-} SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0} SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0} + PLUGIN_API_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + PLUGIN_API_URL: ${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002} + PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-false} + MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev} + PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003} + PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost} + ENDPOINT_URL_TEMPLATE: ${ENDPOINT_URL_TEMPLATE:-http://localhost/e/{hook_id}} depends_on: - db - redis @@ -25,7 +34,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:0.14.2 + image: langgenius/dify-api:dev-plugin-deploy restart: always environment: # Use the shared environment variables. @@ -35,6 +44,12 @@ services: SENTRY_DSN: ${API_SENTRY_DSN:-} SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0} SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0} + PLUGIN_API_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + PLUGIN_API_URL: ${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002} + PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-false} + MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev} depends_on: - db - redis @@ -47,7 +62,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:0.14.2 + image: langgenius/dify-web:dev-plugin-deploy restart: always environment: CONSOLE_API_URL: ${CONSOLE_API_URL:-} @@ -56,6 +71,8 @@ services: NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} CSP_WHITELIST: ${CSP_WHITELIST:-} + MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev} + MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace-plugin.dify.dev} # The postgres database. db: @@ -79,6 +96,8 @@ services: interval: 1s timeout: 3s retries: 30 + ports: + - '${EXPOSE_DB_PORT:-5432}:5432' # The redis cache. redis: @@ -116,6 +135,31 @@ services: networks: - ssrf_proxy_network + # plugin daemon + plugin_daemon: + image: langgenius/dify-plugin-daemon:6ba6c9ace720cfe208d8f3dfd6a9d71ecf0e67c2-local + restart: always + environment: + # Use the shared environment variables. + <<: *shared-api-worker-env + DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin} + SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002} + SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false} + DEBUGGING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} + DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001} + DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0} + PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} + PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd} + ports: + - "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}" + - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" + volumes: + - ./volumes/plugin_daemon:/app/storage + + # ssrf_proxy server # for more information, please refer to # https://docs.dify.ai/learn-more/faq/install-faq#id-18.-why-is-ssrf_proxy-needed diff --git a/docker/docker-compose.middleware.yaml b/docker/docker-compose.middleware.yaml index 11f5302197..aff7418a53 100644 --- a/docker/docker-compose.middleware.yaml +++ b/docker/docker-compose.middleware.yaml @@ -64,6 +64,36 @@ services: networks: - ssrf_proxy_network + # plugin daemon + plugin_daemon: + image: langgenius/dify-plugin-daemon:ac0e7f3d50cfa6c7cb872f2e8353e3b52a7cff0a-local + restart: always + environment: + # Use the shared environment variables. + DB_HOST: ${DB_HOST:-db} + DB_PORT: ${DB_PORT:-5432} + DB_USERNAME: ${DB_USER:-postgres} + DB_PASSWORD: ${DB_PASSWORD:-difyai123456} + DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin} + REDIS_HOST: ${REDIS_HOST:-redis} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_PASSWORD: ${REDIS_PASSWORD:-difyai123456} + SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002} + SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false} + DEBUGGING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} + DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001} + DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0} + PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} + PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd} + ports: + - "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}" + - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" + volumes: + - ./volumes/plugin_daemon:/app/storage + # ssrf_proxy server # for more information, please refer to # https://docs.dify.ai/learn-more/faq/install-faq#id-18.-why-is-ssrf_proxy-needed diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index b82659d959..58c0139b48 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -385,11 +385,27 @@ x-shared-env: &shared-api-worker-env CSP_WHITELIST: ${CSP_WHITELIST:-} CREATE_TIDB_SERVICE_JOB_ENABLED: ${CREATE_TIDB_SERVICE_JOB_ENABLED:-false} MAX_SUBMIT_COUNT: ${MAX_SUBMIT_COUNT:-100} + DB_PLUGIN_DATABASE: ${DB_PLUGIN_DATABASE:-dify-plugin} + EXPOSE_PLUGIN_DAEMON_PORT: ${EXPOSE_PLUGIN_DAEMON_PORT:-5002} + PLUGIN_DAEMON_PORT: ${PLUGIN_DAEMON_PORT:-5002} + PLUGIN_DAEMON_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + PLUGIN_DAEMON_URL: ${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002} + PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + PLUGIN_PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false} + PLUGIN_DEBUGGING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0} + PLUGIN_DEBUGGING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} + EXPOSE_PLUGIN_DEBUGGING_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost} + EXPOSE_PLUGIN_DEBUGGING_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003} + PLUGIN_DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + PLUGIN_DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001} + ENDPOINT_URL_TEMPLATE: ${ENDPOINT_URL_TEMPLATE:-http://localhost/e/{hook_id}} + MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-true} + MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev} services: # API service api: - image: langgenius/dify-api:0.14.2 + image: langgenius/dify-api:dev-plugin-deploy restart: always environment: # Use the shared environment variables. @@ -399,6 +415,15 @@ services: SENTRY_DSN: ${API_SENTRY_DSN:-} SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0} SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0} + PLUGIN_API_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + PLUGIN_API_URL: ${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002} + PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-false} + MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev} + PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003} + PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost} + ENDPOINT_URL_TEMPLATE: ${ENDPOINT_URL_TEMPLATE:-http://localhost/e/{hook_id}} depends_on: - db - redis @@ -412,7 +437,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:0.14.2 + image: langgenius/dify-api:dev-plugin-deploy restart: always environment: # Use the shared environment variables. @@ -422,6 +447,12 @@ services: SENTRY_DSN: ${API_SENTRY_DSN:-} SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0} SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0} + PLUGIN_API_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + PLUGIN_API_URL: ${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002} + PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-false} + MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev} depends_on: - db - redis @@ -434,7 +465,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:0.14.2 + image: langgenius/dify-web:dev-plugin-deploy restart: always environment: CONSOLE_API_URL: ${CONSOLE_API_URL:-} @@ -443,6 +474,8 @@ services: NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0} TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000} CSP_WHITELIST: ${CSP_WHITELIST:-} + MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace-plugin.dify.dev} + MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace-plugin.dify.dev} # The postgres database. db: @@ -466,6 +499,8 @@ services: interval: 1s timeout: 3s retries: 30 + ports: + - '${EXPOSE_DB_PORT:-5432}:5432' # The redis cache. redis: @@ -503,6 +538,31 @@ services: networks: - ssrf_proxy_network + # plugin daemon + plugin_daemon: + image: langgenius/dify-plugin-daemon:6ba6c9ace720cfe208d8f3dfd6a9d71ecf0e67c2-local + restart: always + environment: + # Use the shared environment variables. + <<: *shared-api-worker-env + DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin} + SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002} + SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} + MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} + PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false} + DEBUGGING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} + DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001} + DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} + PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0} + PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} + PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd} + ports: + - "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}" + - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" + volumes: + - ./volumes/plugin_daemon:/app/storage + + # ssrf_proxy server # for more information, please refer to # https://docs.dify.ai/learn-more/faq/install-faq#id-18.-why-is-ssrf_proxy-needed diff --git a/docker/middleware.env.example b/docker/middleware.env.example index c4ce9f0114..31ccc8ed68 100644 --- a/docker/middleware.env.example +++ b/docker/middleware.env.example @@ -87,3 +87,29 @@ EXPOSE_REDIS_PORT=6379 EXPOSE_SANDBOX_PORT=8194 EXPOSE_SSRF_PROXY_PORT=3128 EXPOSE_WEAVIATE_PORT=8080 + +# ------------------------------ +# Plugin Daemon Configuration +# ------------------------------ + +DB_PLUGIN_DATABASE=dify-plugin +EXPOSE_PLUGIN_DAEMON_PORT=5002 +PLUGIN_DAEMON_PORT=5002 +PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi +PLUGIN_DAEMON_URL=http://host.docker.internal:5002 +PLUGIN_MAX_PACKAGE_SIZE=52428800 +PLUGIN_PPROF_ENABLED=false +PLUGIN_WORKING_PATH=/app/storage/cwd + +ENDPOINT_URL_TEMPLATE=http://localhost:5002/e/{hook_id} + +PLUGIN_DEBUGGING_PORT=5003 +PLUGIN_DEBUGGING_HOST=0.0.0.0 +EXPOSE_PLUGIN_DEBUGGING_HOST=localhost +EXPOSE_PLUGIN_DEBUGGING_PORT=5003 + +PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1 +PLUGIN_DIFY_INNER_API_URL=http://api:5001 + +MARKETPLACE_ENABLED=true +MARKETPLACE_API_URL=https://marketplace-plugin.dify.dev diff --git a/docker/nginx/conf.d/default.conf.template b/docker/nginx/conf.d/default.conf.template index 9691122cea..bf86c70735 100644 --- a/docker/nginx/conf.d/default.conf.template +++ b/docker/nginx/conf.d/default.conf.template @@ -24,6 +24,11 @@ server { include proxy.conf; } + location /e { + proxy_pass http://plugin_daemon:5002; + include proxy.conf; + } + location / { proxy_pass http://web:3000; include proxy.conf; From aa6452b3bf20dec05257c942a8394ba87a78970a Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Mon, 6 Jan 2025 21:12:50 +0800 Subject: [PATCH 3/6] fix: use session to manage AppSite --- api/controllers/console/app/site.py | 55 ++++++++++++++++------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/api/controllers/console/app/site.py b/api/controllers/console/app/site.py index db29b95c41..c5a9c4d76e 100644 --- a/api/controllers/console/app/site.py +++ b/api/controllers/console/app/site.py @@ -2,6 +2,7 @@ from datetime import UTC, datetime from flask_login import current_user # type: ignore from flask_restful import Resource, marshal_with, reqparse # type: ignore +from sqlalchemy.orm import Session from werkzeug.exceptions import Forbidden, NotFound from constants.languages import supported_language @@ -50,33 +51,37 @@ class AppSite(Resource): if not current_user.is_editor: raise Forbidden() - site = Site.query.filter(Site.app_id == app_model.id).one_or_404() + with Session(db.engine) as session: + site = session.query(Site).filter(Site.app_id == app_model.id).first() - for attr_name in [ - "title", - "icon_type", - "icon", - "icon_background", - "description", - "default_language", - "chat_color_theme", - "chat_color_theme_inverted", - "customize_domain", - "copyright", - "privacy_policy", - "custom_disclaimer", - "customize_token_strategy", - "prompt_public", - "show_workflow_steps", - "use_icon_as_answer_icon", - ]: - value = args.get(attr_name) - if value is not None: - setattr(site, attr_name, value) + if not site: + raise NotFound - site.updated_by = current_user.id - site.updated_at = datetime.now(UTC).replace(tzinfo=None) - db.session.commit() + for attr_name in [ + "title", + "icon_type", + "icon", + "icon_background", + "description", + "default_language", + "chat_color_theme", + "chat_color_theme_inverted", + "customize_domain", + "copyright", + "privacy_policy", + "custom_disclaimer", + "customize_token_strategy", + "prompt_public", + "show_workflow_steps", + "use_icon_as_answer_icon", + ]: + value = args.get(attr_name) + if value is not None: + setattr(site, attr_name, value) + + site.updated_by = current_user.id + site.updated_at = datetime.now(UTC).replace(tzinfo=None) + session.commit() return site From 8d75abc976611157164c9140eff86f4981b80d98 Mon Sep 17 00:00:00 2001 From: kurokobo Date: Mon, 6 Jan 2025 22:16:39 +0900 Subject: [PATCH 4/6] fix: correct fetch_from for customizable models (#12400) --- api/core/entities/provider_configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/core/entities/provider_configuration.py b/api/core/entities/provider_configuration.py index 0261a6309e..0636234593 100644 --- a/api/core/entities/provider_configuration.py +++ b/api/core/entities/provider_configuration.py @@ -978,7 +978,7 @@ class ProviderConfiguration(BaseModel): label=custom_model_schema.label, model_type=custom_model_schema.model_type, features=custom_model_schema.features, - fetch_from=custom_model_schema.fetch_from, + fetch_from=FetchFrom.CUSTOMIZABLE_MODEL, model_properties=custom_model_schema.model_properties, deprecated=custom_model_schema.deprecated, provider=SimpleModelProviderEntity(self.provider), From 07c7b7b88656afdb276f9c877f89ecfb01696358 Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Mon, 6 Jan 2025 21:45:44 +0800 Subject: [PATCH 5/6] fix: remove 5002 port from docker mapping --- docker/docker-compose-template.yaml | 3 +-- docker/docker-compose.yaml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index 8426e1bcdc..883dc59279 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -137,7 +137,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:6ba6c9ace720cfe208d8f3dfd6a9d71ecf0e67c2-local + image: langgenius/dify-plugin-daemon:ac0e7f3d50cfa6c7cb872f2e8353e3b52a7cff0a-local restart: always environment: # Use the shared environment variables. @@ -154,7 +154,6 @@ services: PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd} ports: - - "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}" - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" volumes: - ./volumes/plugin_daemon:/app/storage diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 58c0139b48..0281f1bed7 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -540,7 +540,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:6ba6c9ace720cfe208d8f3dfd6a9d71ecf0e67c2-local + image: langgenius/dify-plugin-daemon:ac0e7f3d50cfa6c7cb872f2e8353e3b52a7cff0a-local restart: always environment: # Use the shared environment variables. From 9685b9a302e6ae2584c9a7945d719f500efc3062 Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Tue, 7 Jan 2025 14:44:08 +0800 Subject: [PATCH 6/6] refactor: docker-compose-middleware.yaml --- api/.env.example | 5 ++++- docker/docker-compose-template.yaml | 3 +-- docker/docker-compose.middleware.yaml | 3 +-- docker/docker-compose.yaml | 3 +-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/.env.example b/api/.env.example index 4d1358fa69..810ad282a5 100644 --- a/api/.env.example +++ b/api/.env.example @@ -424,12 +424,15 @@ PLUGIN_DAEMON_URL=http://127.0.0.1:5002 PLUGIN_REMOTE_INSTALL_PORT=5003 PLUGIN_REMOTE_INSTALL_HOST=localhost PLUGIN_MAX_PACKAGE_SIZE=15728640 -INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1 +INNER_API_KEY_FOR_PLUGIN=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1 # Marketplace configuration MARKETPLACE_ENABLED=true MARKETPLACE_API_URL=https://marketplace.dify.ai +# Endpoint configuration +ENDPOINT_URL_TEMPLATE=http://localhost/e/{hook_id} + # Reset password token expiry minutes RESET_PASSWORD_TOKEN_EXPIRY_MINUTES=5 diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index 883dc59279..64f02a26f8 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -137,7 +137,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:ac0e7f3d50cfa6c7cb872f2e8353e3b52a7cff0a-local + image: langgenius/dify-plugin-daemon:47c8bed17c22f67bd035d0979e696cb00ca45b16-local restart: always environment: # Use the shared environment variables. @@ -147,7 +147,6 @@ services: SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false} - DEBUGGING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001} DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0} diff --git a/docker/docker-compose.middleware.yaml b/docker/docker-compose.middleware.yaml index aff7418a53..4cbd2a776a 100644 --- a/docker/docker-compose.middleware.yaml +++ b/docker/docker-compose.middleware.yaml @@ -66,7 +66,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:ac0e7f3d50cfa6c7cb872f2e8353e3b52a7cff0a-local + image: langgenius/dify-plugin-daemon:47c8bed17c22f67bd035d0979e696cb00ca45b16-local restart: always environment: # Use the shared environment variables. @@ -82,7 +82,6 @@ services: SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi} MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800} PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false} - DEBUGGING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001} DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1} PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0} diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 0281f1bed7..be70e27354 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -540,7 +540,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:ac0e7f3d50cfa6c7cb872f2e8353e3b52a7cff0a-local + image: langgenius/dify-plugin-daemon:47c8bed17c22f67bd035d0979e696cb00ca45b16-local restart: always environment: # Use the shared environment variables. @@ -557,7 +557,6 @@ services: PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003} PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd} ports: - - "${EXPOSE_PLUGIN_DAEMON_PORT:-5002}:${PLUGIN_DAEMON_PORT:-5002}" - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}" volumes: - ./volumes/plugin_daemon:/app/storage