From ba9357da9680c34d5f429043062893dc4945c6cc Mon Sep 17 00:00:00 2001 From: Yeuoly <45712896+Yeuoly@users.noreply.github.com> Date: Wed, 23 Apr 2025 15:29:58 +0800 Subject: [PATCH 01/20] fix: handle PluginPermissionDeniedError in EndpointCreateApi (#18597) --- api/controllers/console/workspace/endpoint.py | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/api/controllers/console/workspace/endpoint.py b/api/controllers/console/workspace/endpoint.py index a5bd2a4bcf..46dee20f8b 100644 --- a/api/controllers/console/workspace/endpoint.py +++ b/api/controllers/console/workspace/endpoint.py @@ -5,6 +5,7 @@ from werkzeug.exceptions import Forbidden from controllers.console import api from controllers.console.wraps import account_initialization_required, setup_required from core.model_runtime.utils.encoders import jsonable_encoder +from core.plugin.manager.exc import PluginPermissionDeniedError from libs.login import login_required from services.plugin.endpoint_service import EndpointService @@ -28,15 +29,18 @@ class EndpointCreateApi(Resource): settings = args["settings"] name = args["name"] - return { - "success": EndpointService.create_endpoint( - tenant_id=user.current_tenant_id, - user_id=user.id, - plugin_unique_identifier=plugin_unique_identifier, - name=name, - settings=settings, - ) - } + try: + return { + "success": EndpointService.create_endpoint( + tenant_id=user.current_tenant_id, + user_id=user.id, + plugin_unique_identifier=plugin_unique_identifier, + name=name, + settings=settings, + ) + } + except PluginPermissionDeniedError as e: + raise ValueError(e.description) from e class EndpointListApi(Resource): From 5e09ac696c0c1030d4f660707fe8b53b146dbc40 Mon Sep 17 00:00:00 2001 From: jayeeliu Date: Wed, 23 Apr 2025 14:43:19 +0700 Subject: [PATCH 02/20] fix: add composer configuration and delete DifyClient->file_client (#18574) --- sdks/php-client/.gitignore | 1 + sdks/php-client/README.md | 19 +- sdks/php-client/composer.json | 9 + sdks/php-client/composer.lock | 663 ++++++++++++++++++++++++++++++++ sdks/php-client/dify-client.php | 20 +- 5 files changed, 693 insertions(+), 19 deletions(-) create mode 100644 sdks/php-client/.gitignore create mode 100644 sdks/php-client/composer.json create mode 100644 sdks/php-client/composer.lock diff --git a/sdks/php-client/.gitignore b/sdks/php-client/.gitignore new file mode 100644 index 0000000000..61ead86667 --- /dev/null +++ b/sdks/php-client/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/sdks/php-client/README.md b/sdks/php-client/README.md index b0a435bbaf..812980d834 100644 --- a/sdks/php-client/README.md +++ b/sdks/php-client/README.md @@ -9,6 +9,21 @@ This is the PHP SDK for the Dify API, which allows you to easily integrate Dify ## Usage +If you want to try the example, you can run `composer install` in this directory. + +In exist project, copy the `dify-client.php` to you project, and merge the following to your `composer.json` file, then run `composer install && composer dump-autoload` to install. Guzzle does not require 7.9, other versions have not been tested, but you can try. + +```json +{ + "require": { + "guzzlehttp/guzzle": "^7.9" + }, + "autoload": { + "files": ["path/to/dify-client.php"] + } +} +``` + After installing the SDK, you can use it in your project like this: ```php @@ -16,10 +31,6 @@ After installing the SDK, you can use it in your project like this: require 'vendor/autoload.php'; -use YourVendorName\DifyPHP\DifyClient; -use YourVendorName\DifyPHP\CompletionClient; -use YourVendorName\DifyPHP\ChatClient; - $apiKey = 'your-api-key-here'; $difyClient = new DifyClient($apiKey); diff --git a/sdks/php-client/composer.json b/sdks/php-client/composer.json new file mode 100644 index 0000000000..6e49e44075 --- /dev/null +++ b/sdks/php-client/composer.json @@ -0,0 +1,9 @@ +{ + "require": { + "php": ">=7.2", + "guzzlehttp/guzzle": "^7.9" + }, + "autoload": { + "files": ["dify-client.php"] + } +} diff --git a/sdks/php-client/composer.lock b/sdks/php-client/composer.lock new file mode 100644 index 0000000000..aa07dc03ef --- /dev/null +++ b/sdks/php-client/composer.lock @@ -0,0 +1,663 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "7827c548fdcc7e87cb0ae341dd2c6b1b", + "packages": [ + { + "name": "guzzlehttp/guzzle", + "version": "7.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2024-07-24T11:22:20+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.2.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:27:01+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-03-27T12:30:47+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "e616d01114759c4c489f93b099585439f795fe35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + }, + "time": "2023-04-10T20:10:41+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/sdks/php-client/dify-client.php b/sdks/php-client/dify-client.php index ccd61f091a..acb862093a 100644 --- a/sdks/php-client/dify-client.php +++ b/sdks/php-client/dify-client.php @@ -1,7 +1,5 @@ api_key = $api_key; - $this->base_url = $base_url ?? "https://api.dify.ai/v1/"; + $this->base_url = $base_url ?? 'https://api.dify.ai/v1/'; $this->client = new Client([ 'base_uri' => $this->base_url, 'headers' => [ @@ -19,13 +17,6 @@ class DifyClient { 'Content-Type' => 'application/json', ], ]); - $this->file_client = new Client([ - 'base_uri' => $this->base_url, - 'headers' => [ - 'Authorization' => 'Bearer ' . $this->api_key, - 'Content-Type' => 'multipart/form-data', - ], - ]); } protected function send_request($method, $endpoint, $data = null, $params = null, $stream = false) { @@ -58,7 +49,7 @@ class DifyClient { 'multipart' => $this->prepareMultipart($data, $files) ]; - return $this->file_client->request('POST', 'files/upload', $options); + return $this->client->request('POST', 'files/upload', $options); } protected function prepareMultipart($data, $files) { @@ -132,7 +123,7 @@ class ChatClient extends DifyClient { public function get_suggestions($message_id, $user) { $params = [ 'user' => $user - ] + ]; return $this->send_request('GET', "messages/{$message_id}/suggested", null, $params); } @@ -188,10 +179,9 @@ class ChatClient extends DifyClient { 'user' => $user, ]; $options = [ - 'multipart' => $this->prepareMultipart($data, $files) + 'multipart' => $this->prepareMultipart($data, $audio_file) ]; - return $this->file_client->request('POST', 'audio-to-text', $options); - + return $this->client->request('POST', 'audio-to-text', $options); } } From cf464d252dfc3124522796ee9a08cdbde93a6174 Mon Sep 17 00:00:00 2001 From: onlysyz <296260444@qq.com> Date: Wed, 23 Apr 2025 15:55:46 +0800 Subject: [PATCH 03/20] fix#18595: update workflow duplicate env variable name (#18596) Co-authored-by: tiankuo.zhou --- .../workflow/panel/env-panel/variable-modal.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/app/components/workflow/panel/env-panel/variable-modal.tsx b/web/app/components/workflow/panel/env-panel/variable-modal.tsx index f7dfbad892..4546aabae6 100644 --- a/web/app/components/workflow/panel/env-panel/variable-modal.tsx +++ b/web/app/components/workflow/panel/env-panel/variable-modal.tsx @@ -47,8 +47,14 @@ const VariableModal = ({ return if (!value) return notify({ type: 'error', message: 'value can not be empty' }) - if (!env && envList.some(env => env.name === name)) + + // Add check for duplicate name when editing + if (env && env.name !== name && envList.some(e => e.name === name)) + return notify({ type: 'error', message: 'name is existed' }) + // Original check for create new variable + if (!env && envList.some(e => e.name === name)) return notify({ type: 'error', message: 'name is existed' }) + onSave({ id: env ? env.id : uuid4(), value_type: type, From e9aedc701c5a41405d855ea85a6ad121c5fa7b13 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Wed, 23 Apr 2025 17:26:55 +0900 Subject: [PATCH 04/20] chore: Updates version numbers for upcoming release (#18550) Signed-off-by: -LAN- --- api/configs/packaging/__init__.py | 2 +- api/services/app_dsl_service.py | 2 +- docker/docker-compose-template.yaml | 8 ++++---- docker/docker-compose.middleware.yaml | 2 +- docker/docker-compose.yaml | 8 ++++---- web/package.json | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/api/configs/packaging/__init__.py b/api/configs/packaging/__init__.py index c7aedc5b8a..a33c7727dc 100644 --- a/api/configs/packaging/__init__.py +++ b/api/configs/packaging/__init__.py @@ -9,7 +9,7 @@ class PackagingInfo(BaseSettings): CURRENT_VERSION: str = Field( description="Dify version", - default="1.2.0", + default="1.3.0", ) COMMIT_SHA: str = Field( diff --git a/api/services/app_dsl_service.py b/api/services/app_dsl_service.py index 2e2b729021..936101c78c 100644 --- a/api/services/app_dsl_service.py +++ b/api/services/app_dsl_service.py @@ -40,7 +40,7 @@ IMPORT_INFO_REDIS_KEY_PREFIX = "app_import_info:" CHECK_DEPENDENCIES_REDIS_KEY_PREFIX = "app_check_dependencies:" IMPORT_INFO_REDIS_EXPIRY = 10 * 60 # 10 minutes DSL_MAX_SIZE = 10 * 1024 * 1024 # 10MB -CURRENT_DSL_VERSION = "0.1.5" +CURRENT_DSL_VERSION = "0.2.0" class ImportMode(StrEnum): diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index 377ff9c117..8c57a7c4c2 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:1.2.0 + image: langgenius/dify-api:1.3.0 restart: always environment: # Use the shared environment variables. @@ -31,7 +31,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:1.2.0 + image: langgenius/dify-api:1.3.0 restart: always environment: # Use the shared environment variables. @@ -57,7 +57,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:1.2.0 + image: langgenius/dify-web:1.3.0 restart: always environment: CONSOLE_API_URL: ${CONSOLE_API_URL:-} @@ -142,7 +142,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:0.0.7-local + image: langgenius/dify-plugin-daemon:0.0.8-local restart: always environment: # Use the shared environment variables. diff --git a/docker/docker-compose.middleware.yaml b/docker/docker-compose.middleware.yaml index 1702a5395f..fc08edd264 100644 --- a/docker/docker-compose.middleware.yaml +++ b/docker/docker-compose.middleware.yaml @@ -71,7 +71,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:0.0.7-local + image: langgenius/dify-plugin-daemon:0.0.8-local restart: always env_file: - ./middleware.env diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 81fa651ed9..3d3e3a901f 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -479,7 +479,7 @@ x-shared-env: &shared-api-worker-env services: # API service api: - image: langgenius/dify-api:1.2.0 + image: langgenius/dify-api:1.3.0 restart: always environment: # Use the shared environment variables. @@ -508,7 +508,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:1.2.0 + image: langgenius/dify-api:1.3.0 restart: always environment: # Use the shared environment variables. @@ -534,7 +534,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:1.2.0 + image: langgenius/dify-web:1.3.0 restart: always environment: CONSOLE_API_URL: ${CONSOLE_API_URL:-} @@ -619,7 +619,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:0.0.7-local + image: langgenius/dify-plugin-daemon:0.0.8-local restart: always environment: # Use the shared environment variables. diff --git a/web/package.json b/web/package.json index 714ec87695..b232f908a3 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "dify-web", - "version": "1.2.0", + "version": "1.3.0", "private": true, "engines": { "node": ">=v22.11.0" From 205535c8e9221a1012a558df73fd42c36e285b1c Mon Sep 17 00:00:00 2001 From: Will Date: Wed, 23 Apr 2025 16:48:00 +0800 Subject: [PATCH 05/20] chore: fix reimported (#18610) --- api/controllers/console/app/audio.py | 2 -- api/models/model.py | 7 ++----- api/models/workflow.py | 4 +--- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/api/controllers/console/app/audio.py b/api/controllers/console/app/audio.py index 12d9157dda..7519ae96c0 100644 --- a/api/controllers/console/app/audio.py +++ b/api/controllers/console/app/audio.py @@ -80,8 +80,6 @@ class ChatMessageTextApi(Resource): @account_initialization_required @get_app_model def post(self, app_model: App): - from werkzeug.exceptions import InternalServerError - try: parser = reqparse.RequestParser() parser.add_argument("message_id", type=str, location="json") diff --git a/api/models/model.py b/api/models/model.py index 6577492d1b..d1490d75c8 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -3,8 +3,8 @@ import re import uuid from collections.abc import Mapping from datetime import datetime -from enum import Enum -from typing import TYPE_CHECKING, Optional +from enum import Enum, StrEnum +from typing import TYPE_CHECKING, Any, Literal, Optional, cast from core.plugin.entities.plugin import GenericProviderID from core.tools.entities.tool_entities import ToolProviderType @@ -13,9 +13,6 @@ from services.plugin.plugin_service import PluginService if TYPE_CHECKING: from models.workflow import Workflow -from enum import StrEnum -from typing import TYPE_CHECKING, Any, Literal, cast - import sqlalchemy as sa from flask import request from flask_login import UserMixin # type: ignore diff --git a/api/models/workflow.py b/api/models/workflow.py index 5a67fa47a8..da60617de5 100644 --- a/api/models/workflow.py +++ b/api/models/workflow.py @@ -1,14 +1,12 @@ import json from collections.abc import Mapping, Sequence from datetime import UTC, datetime -from enum import Enum +from enum import Enum, StrEnum from typing import TYPE_CHECKING, Any, Optional, Self, Union from uuid import uuid4 if TYPE_CHECKING: from models.model import AppMode -from enum import StrEnum -from typing import TYPE_CHECKING import sqlalchemy as sa from sqlalchemy import Index, PrimaryKeyConstraint, func From d5fe50e47104a39cbf0a1f14b2dd9168d03f1c09 Mon Sep 17 00:00:00 2001 From: "Junjie.M" <118170653@qq.com> Date: Wed, 23 Apr 2025 16:48:45 +0800 Subject: [PATCH 06/20] embedding in websites support initializes to specify the conversation_id (#18602) --- web/app/components/app/overview/embedded/index.tsx | 1 + web/app/components/base/chat/embedded-chatbot/hooks.tsx | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/web/app/components/app/overview/embedded/index.tsx b/web/app/components/app/overview/embedded/index.tsx index d4e5dd8898..6ebd0fce69 100644 --- a/web/app/components/app/overview/embedded/index.tsx +++ b/web/app/components/app/overview/embedded/index.tsx @@ -48,6 +48,7 @@ const OPTION_MAP = { : ''}, systemVariables: { // user_id: 'YOU CAN DEFINE USER ID HERE', + // conversation_id: 'YOU CAN DEFINE CONVERSATION ID HERE, IT MUST BE A VALID UUID', }, } diff --git a/web/app/components/base/chat/embedded-chatbot/hooks.tsx b/web/app/components/base/chat/embedded-chatbot/hooks.tsx index 0f2529152c..cfd2acb17f 100644 --- a/web/app/components/base/chat/embedded-chatbot/hooks.tsx +++ b/web/app/components/base/chat/embedded-chatbot/hooks.tsx @@ -73,9 +73,11 @@ export const useEmbeddedChatbot = () => { const appId = useMemo(() => appData?.app_id, [appData]) const [userId, setUserId] = useState() + const [conversationId, setConversationId] = useState() useEffect(() => { - getProcessedSystemVariablesFromUrlParams().then(({ user_id }) => { + getProcessedSystemVariablesFromUrlParams().then(({ user_id, conversation_id }) => { setUserId(user_id) + setConversationId(conversation_id) }) }, []) @@ -109,7 +111,8 @@ export const useEmbeddedChatbot = () => { const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState>>(CONVERSATION_ID_INFO, { defaultValue: {}, }) - const currentConversationId = useMemo(() => conversationIdInfo?.[appId || '']?.[userId || 'DEFAULT'] || '', [appId, conversationIdInfo, userId]) + const currentConversationId = useMemo(() => conversationIdInfo?.[appId || '']?.[userId || 'DEFAULT'] || conversationId || '', + [appId, conversationIdInfo, userId, conversationId]) const handleConversationIdInfoChange = useCallback((changeConversationId: string) => { if (appId) { let prevValue = conversationIdInfo?.[appId || ''] From d7c3e54eaafe61dc9980d8cbab42049c160247c8 Mon Sep 17 00:00:00 2001 From: minglu7 <1347866672@qq.com> Date: Wed, 23 Apr 2025 17:06:17 +0800 Subject: [PATCH 07/20] fix: improve translation of community code of conduct sentence (#18607) --- CONTRIBUTING_CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING_CN.md b/CONTRIBUTING_CN.md index 0478d2e1fa..69ae7071bb 100644 --- a/CONTRIBUTING_CN.md +++ b/CONTRIBUTING_CN.md @@ -6,7 +6,7 @@ 本指南和 Dify 一样在不断完善中。如果有任何滞后于项目实际情况的地方,恳请谅解,我们也欢迎任何改进建议。 -关于许可证,请花一分钟阅读我们简短的[许可和贡献者协议](./LICENSE)。社区同时也遵循[行为准则](https://github.com/langgenius/.github/blob/main/CODE_OF_CONDUCT.md)。 +关于许可证,请花一分钟阅读我们简短的[许可和贡献者协议](./LICENSE)。同时也请遵循社区[行为准则](https://github.com/langgenius/.github/blob/main/CODE_OF_CONDUCT.md)。 ## 开始之前 From c479fcf251bc2bfdc8ed2a7cff29de7ef5d829e3 Mon Sep 17 00:00:00 2001 From: crazywoola <100913391+crazywoola@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:02:18 +0800 Subject: [PATCH 08/20] feat: add missing switches (#18619) --- web/app/layout.tsx | 3 +++ web/config/index.ts | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/web/app/layout.tsx b/web/app/layout.tsx index 6b5618f217..438f56d363 100644 --- a/web/app/layout.tsx +++ b/web/app/layout.tsx @@ -54,6 +54,9 @@ const LocaleLayout = async ({ data-public-indexing-max-segmentation-tokens-length={process.env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH} data-public-loop-node-max-count={process.env.NEXT_PUBLIC_LOOP_NODE_MAX_COUNT} data-public-max-iterations-num={process.env.NEXT_PUBLIC_MAX_ITERATIONS_NUM} + data-public-enable-website-jinareader={process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER} + data-public-enable-website-firecrawl={process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL} + data-public-enable-website-watercrawl={process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL} > diff --git a/web/config/index.ts b/web/config/index.ts index 3466686293..af4da76835 100644 --- a/web/config/index.ts +++ b/web/config/index.ts @@ -306,12 +306,12 @@ export const MAX_ITERATIONS_NUM = maxIterationsNum export const ENABLE_WEBSITE_JINAREADER = process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER !== undefined ? process.env.NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER === 'true' - : true + : globalThis.document?.body?.getAttribute('data-public-enable-website-jinareader') === 'true' || true export const ENABLE_WEBSITE_FIRECRAWL = process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL !== undefined ? process.env.NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL === 'true' - : true + : globalThis.document?.body?.getAttribute('data-public-enable-website-firecrawl') === 'true' || true export const ENABLE_WEBSITE_WATERCRAWL = process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL !== undefined ? process.env.NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL === 'true' - : true + : globalThis.document?.body?.getAttribute('data-public-enable-website-watercrawl') === 'true' || true From b2031393560294f7d59f133a35b84c2288189504 Mon Sep 17 00:00:00 2001 From: "Junjie.M" <118170653@qq.com> Date: Wed, 23 Apr 2025 22:57:42 +0800 Subject: [PATCH 09/20] embedding in websites setting conversation_id requires hiding reset conversation button (#18623) --- web/app/components/base/chat/embedded-chatbot/context.tsx | 2 ++ .../components/base/chat/embedded-chatbot/header/index.tsx | 6 ++++-- web/app/components/base/chat/embedded-chatbot/hooks.tsx | 2 ++ web/app/components/base/chat/embedded-chatbot/index.tsx | 4 ++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/web/app/components/base/chat/embedded-chatbot/context.tsx b/web/app/components/base/chat/embedded-chatbot/context.tsx index eb5e9d697f..fb00dbd64d 100644 --- a/web/app/components/base/chat/embedded-chatbot/context.tsx +++ b/web/app/components/base/chat/embedded-chatbot/context.tsx @@ -39,6 +39,7 @@ export type EmbeddedChatbotContextValue = { chatShouldReloadKey: string isMobile: boolean isInstalledApp: boolean + allowResetChat: boolean appId?: string handleFeedback: (messageId: string, feedback: Feedback) => void currentChatInstanceRef: RefObject<{ handleStop: () => void }> @@ -67,6 +68,7 @@ export const EmbeddedChatbotContext = createContext chatShouldReloadKey: '', isMobile: false, isInstalledApp: false, + allowResetChat: true, handleFeedback: noop, currentChatInstanceRef: { current: { handleStop: noop } }, clearChatList: false, diff --git a/web/app/components/base/chat/embedded-chatbot/header/index.tsx b/web/app/components/base/chat/embedded-chatbot/header/index.tsx index d05e7a650c..c38a4546dd 100644 --- a/web/app/components/base/chat/embedded-chatbot/header/index.tsx +++ b/web/app/components/base/chat/embedded-chatbot/header/index.tsx @@ -16,6 +16,7 @@ import cn from '@/utils/classnames' export type IHeaderProps = { isMobile?: boolean + allowResetChat?: boolean customerIcon?: React.ReactNode title: string theme?: Theme @@ -23,6 +24,7 @@ export type IHeaderProps = { } const Header: FC = ({ isMobile, + allowResetChat, customerIcon, title, theme, @@ -57,7 +59,7 @@ const Header: FC = ({ {currentConversationId && ( )} - {currentConversationId && ( + {currentConversationId && allowResetChat && ( @@ -89,7 +91,7 @@ const Header: FC = ({
- {currentConversationId && ( + {currentConversationId && allowResetChat && ( diff --git a/web/app/components/base/chat/embedded-chatbot/hooks.tsx b/web/app/components/base/chat/embedded-chatbot/hooks.tsx index cfd2acb17f..7efbc95dee 100644 --- a/web/app/components/base/chat/embedded-chatbot/hooks.tsx +++ b/web/app/components/base/chat/embedded-chatbot/hooks.tsx @@ -111,6 +111,7 @@ export const useEmbeddedChatbot = () => { const [conversationIdInfo, setConversationIdInfo] = useLocalStorageState>>(CONVERSATION_ID_INFO, { defaultValue: {}, }) + const allowResetChat = !conversationId const currentConversationId = useMemo(() => conversationIdInfo?.[appId || '']?.[userId || 'DEFAULT'] || conversationId || '', [appId, conversationIdInfo, userId, conversationId]) const handleConversationIdInfoChange = useCallback((changeConversationId: string) => { @@ -365,6 +366,7 @@ export const useEmbeddedChatbot = () => { appInfoError, appInfoLoading, isInstalledApp, + allowResetChat, appId, currentConversationId, currentConversationItem, diff --git a/web/app/components/base/chat/embedded-chatbot/index.tsx b/web/app/components/base/chat/embedded-chatbot/index.tsx index aaf59ca4e4..96dff67bf4 100644 --- a/web/app/components/base/chat/embedded-chatbot/index.tsx +++ b/web/app/components/base/chat/embedded-chatbot/index.tsx @@ -25,6 +25,7 @@ import cn from '@/utils/classnames' const Chatbot = () => { const { isMobile, + allowResetChat, appInfoError, appInfoLoading, appData, @@ -90,6 +91,7 @@ const Chatbot = () => { >
{ handleNewConversationCompleted, chatShouldReloadKey, isInstalledApp, + allowResetChat, appId, handleFeedback, currentChatInstanceRef, @@ -187,6 +190,7 @@ const EmbeddedChatbotWrapper = () => { chatShouldReloadKey, isMobile, isInstalledApp, + allowResetChat, appId, handleFeedback, currentChatInstanceRef, From dd02a9ac9d8d49d8b06bfcc8d6b085b1d3e59700 Mon Sep 17 00:00:00 2001 From: GuanMu Date: Wed, 23 Apr 2025 23:17:28 +0800 Subject: [PATCH 10/20] fix: enhance TOC navigation with scrollable overflow for better usability (#18636) --- web/app/components/develop/doc.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/components/develop/doc.tsx b/web/app/components/develop/doc.tsx index deda6dc8b8..12a273ea9c 100644 --- a/web/app/components/develop/doc.tsx +++ b/web/app/components/develop/doc.tsx @@ -87,7 +87,7 @@ const Doc = ({ appDetail }: IDocProps) => {
{isTocExpanded ? ( -