diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b4a6eb9adb..f4a5f754e0 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,25 +1,23 @@ -# Summary +> [!IMPORTANT] +> +> 1. Make sure you have read our [contribution guidelines](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) +> 2. Ensure there is an associated issue and you have been assigned to it +> 3. Use the correct syntax to link this PR: `Fixes #`. -Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. +## Summary -> [!Tip] -> Close issue syntax: `Fixes #` or `Resolves #`, see [documentation](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) for more details. + - -# Screenshots +## Screenshots | Before | After | |--------|-------| | ... | ... | -# Checklist - -> [!IMPORTANT] -> Please review the checklist below before submitting your pull request. +## Checklist - [ ] This change requires a documentation update, included: [Dify Document](https://github.com/langgenius/dify-docs) - [x] I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!) - [x] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. - [x] I've updated the documentation accordingly. - [x] I ran `dev/reformat`(backend) and `cd web && npx lint-staged`(frontend) to appease the lint gods - diff --git a/api/controllers/service_api/app/annotation.py b/api/controllers/service_api/app/annotation.py index 1a7f0c935b..595ae118ef 100644 --- a/api/controllers/service_api/app/annotation.py +++ b/api/controllers/service_api/app/annotation.py @@ -9,13 +9,13 @@ from fields.annotation_fields import ( annotation_fields, ) from libs.login import current_user -from models.model import App, EndUser +from models.model import App from services.annotation_service import AppAnnotationService class AnnotationReplyActionApi(Resource): @validate_app_token - def post(self, app_model: App, end_user: EndUser, action): + def post(self, app_model: App, action): parser = reqparse.RequestParser() parser.add_argument("score_threshold", required=True, type=float, location="json") parser.add_argument("embedding_provider_name", required=True, type=str, location="json") @@ -32,7 +32,7 @@ class AnnotationReplyActionApi(Resource): class AnnotationReplyActionStatusApi(Resource): @validate_app_token - def get(self, app_model: App, end_user: EndUser, job_id, action): + def get(self, app_model: App, job_id, action): job_id = str(job_id) app_annotation_job_key = "{}_app_annotation_job_{}".format(action, str(job_id)) cache_result = redis_client.get(app_annotation_job_key) @@ -50,7 +50,7 @@ class AnnotationReplyActionStatusApi(Resource): class AnnotationListApi(Resource): @validate_app_token - def get(self, app_model: App, end_user: EndUser): + def get(self, app_model: App): page = request.args.get("page", default=1, type=int) limit = request.args.get("limit", default=20, type=int) keyword = request.args.get("keyword", default="", type=str) @@ -67,7 +67,7 @@ class AnnotationListApi(Resource): @validate_app_token @marshal_with(annotation_fields) - def post(self, app_model: App, end_user: EndUser): + def post(self, app_model: App): parser = reqparse.RequestParser() parser.add_argument("question", required=True, type=str, location="json") parser.add_argument("answer", required=True, type=str, location="json") @@ -79,7 +79,7 @@ class AnnotationListApi(Resource): class AnnotationUpdateDeleteApi(Resource): @validate_app_token @marshal_with(annotation_fields) - def put(self, app_model: App, end_user: EndUser, annotation_id): + def put(self, app_model: App, annotation_id): if not current_user.is_editor: raise Forbidden() @@ -92,7 +92,7 @@ class AnnotationUpdateDeleteApi(Resource): return annotation @validate_app_token - def delete(self, app_model: App, end_user: EndUser, annotation_id): + def delete(self, app_model: App, annotation_id): if not current_user.is_editor: raise Forbidden() diff --git a/api/core/plugin/impl/base.py b/api/core/plugin/impl/base.py index 591e7b0525..7b9592bff3 100644 --- a/api/core/plugin/impl/base.py +++ b/api/core/plugin/impl/base.py @@ -6,6 +6,7 @@ from typing import TypeVar import requests from pydantic import BaseModel +from requests.exceptions import HTTPError from yarl import URL from configs import dify_config @@ -136,12 +137,31 @@ class BasePluginClient: """ Make a request to the plugin daemon inner API and return the response as a model. """ - response = self._request(method, path, headers, data, params, files) - json_response = response.json() - if transformer: - json_response = transformer(json_response) + try: + response = self._request(method, path, headers, data, params, files) + response.raise_for_status() + except HTTPError as e: + msg = f"Failed to request plugin daemon, status: {e.response.status_code}, url: {path}" + logging.exception(msg) + raise e + except Exception as e: + msg = f"Failed to request plugin daemon, url: {path}" + logging.exception(msg) + raise ValueError(msg) from e + + try: + json_response = response.json() + if transformer: + json_response = transformer(json_response) + rep = PluginDaemonBasicResponse[type](**json_response) # type: ignore + except Exception: + msg = ( + f"Failed to parse response from plugin daemon to PluginDaemonBasicResponse [{str(type.__name__)}]," + f" url: {path}" + ) + logging.exception(msg) + raise ValueError(msg) - rep = PluginDaemonBasicResponse[type](**json_response) # type: ignore if rep.code != 0: try: error = PluginDaemonError(**json.loads(rep.message)) diff --git a/api/core/workflow/nodes/code/code_node.py b/api/core/workflow/nodes/code/code_node.py index 804c05f9f4..59dae792e8 100644 --- a/api/core/workflow/nodes/code/code_node.py +++ b/api/core/workflow/nodes/code/code_node.py @@ -167,8 +167,11 @@ class CodeNode(BaseNode[CodeNodeData]): value=value, variable=f"{prefix}.{output_name}[{i}]" if prefix else f"{output_name}[{i}]", ) - elif isinstance(first_element, dict) and all( - value is None or isinstance(value, dict) for value in output_value + elif ( + isinstance(first_element, dict) + and all(value is None or isinstance(value, dict) for value in output_value) + or isinstance(first_element, list) + and all(value is None or isinstance(value, list) for value in output_value) ): for i, value in enumerate(output_value): if value is not None: diff --git a/docker/middleware.env.example b/docker/middleware.env.example index 2437026eec..ba6859885b 100644 --- a/docker/middleware.env.example +++ b/docker/middleware.env.example @@ -109,7 +109,7 @@ 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 +PLUGIN_DIFY_INNER_API_URL=http://host.docker.internal:5001 MARKETPLACE_ENABLED=true MARKETPLACE_API_URL=https://marketplace.dify.ai diff --git a/web/app/components/custom/custom-web-app-brand/index.tsx b/web/app/components/custom/custom-web-app-brand/index.tsx index f6f617be85..ea2f44caea 100644 --- a/web/app/components/custom/custom-web-app-brand/index.tsx +++ b/web/app/components/custom/custom-web-app-brand/index.tsx @@ -130,7 +130,7 @@ const CustomWebAppBrand = () => {
{t('custom.webapp.changeLogoTip')}
- {(uploadDisabled || (!webappLogo && !webappBrandRemoved)) && ( + {(!uploadDisabled && webappLogo && !webappBrandRemoved) && ( <>