diff --git a/api/configs/feature/__init__.py b/api/configs/feature/__init__.py index 9e2ba41780..ba3542baf3 100644 --- a/api/configs/feature/__init__.py +++ b/api/configs/feature/__init__.py @@ -498,6 +498,11 @@ class AuthConfig(BaseSettings): default=86400, ) + FORGOT_PASSWORD_LOCKOUT_DURATION: PositiveInt = Field( + description="Time (in seconds) a user must wait before retrying password reset after exceeding the rate limit.", + default=86400, + ) + class ModerationConfig(BaseSettings): """ diff --git a/api/configs/packaging/__init__.py b/api/configs/packaging/__init__.py index 20c1f58c99..fd3d6afb3a 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="0.15.2", + default="0.15.3", ) COMMIT_SHA: str = Field( diff --git a/api/controllers/console/auth/error.py b/api/controllers/console/auth/error.py index 8ef10c7bbb..b40934dbf5 100644 --- a/api/controllers/console/auth/error.py +++ b/api/controllers/console/auth/error.py @@ -59,3 +59,9 @@ class EmailCodeAccountDeletionRateLimitExceededError(BaseHTTPException): error_code = "email_code_account_deletion_rate_limit_exceeded" description = "Too many account deletion emails have been sent. Please try again in 5 minutes." code = 429 + + +class EmailPasswordResetLimitError(BaseHTTPException): + error_code = "email_password_reset_limit" + description = "Too many failed password reset attempts. Please try again in 24 hours." + code = 429 diff --git a/api/controllers/console/auth/forgot_password.py b/api/controllers/console/auth/forgot_password.py index a9c4300b9a..241ecdbd53 100644 --- a/api/controllers/console/auth/forgot_password.py +++ b/api/controllers/console/auth/forgot_password.py @@ -6,7 +6,13 @@ from flask_restful import Resource, reqparse # type: ignore from constants.languages import languages from controllers.console import api -from controllers.console.auth.error import EmailCodeError, InvalidEmailError, InvalidTokenError, PasswordMismatchError +from controllers.console.auth.error import ( + EmailCodeError, + EmailPasswordResetLimitError, + InvalidEmailError, + InvalidTokenError, + PasswordMismatchError, +) from controllers.console.error import AccountInFreezeError, AccountNotFound, EmailSendIpLimitError from controllers.console.wraps import setup_required from events.tenant_event import tenant_was_created @@ -62,6 +68,10 @@ class ForgotPasswordCheckApi(Resource): user_email = args["email"] + is_forgot_password_error_rate_limit = AccountService.is_forgot_password_error_rate_limit(args["email"]) + if is_forgot_password_error_rate_limit: + raise EmailPasswordResetLimitError() + token_data = AccountService.get_reset_password_data(args["token"]) if token_data is None: raise InvalidTokenError() @@ -70,8 +80,10 @@ class ForgotPasswordCheckApi(Resource): raise InvalidEmailError() if args["code"] != token_data.get("code"): + AccountService.add_forgot_password_error_rate_limit(args["email"]) raise EmailCodeError() + AccountService.reset_forgot_password_error_rate_limit(args["email"]) return {"is_valid": True, "email": token_data.get("email")} diff --git a/api/core/model_runtime/entities/__init__.py b/api/core/model_runtime/entities/__init__.py index c3e1351e3b..4746ddedcf 100644 --- a/api/core/model_runtime/entities/__init__.py +++ b/api/core/model_runtime/entities/__init__.py @@ -1,4 +1,4 @@ -from .llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage +from .llm_entities import LLMMode, LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage from .message_entities import ( AssistantPromptMessage, AudioPromptMessageContent, @@ -23,6 +23,7 @@ __all__ = [ "AudioPromptMessageContent", "DocumentPromptMessageContent", "ImagePromptMessageContent", + "LLMMode", "LLMResult", "LLMResultChunk", "LLMResultChunkDelta", diff --git a/api/core/model_runtime/entities/llm_entities.py b/api/core/model_runtime/entities/llm_entities.py index 88531d8ae0..4523da4388 100644 --- a/api/core/model_runtime/entities/llm_entities.py +++ b/api/core/model_runtime/entities/llm_entities.py @@ -1,5 +1,5 @@ from decimal import Decimal -from enum import Enum +from enum import StrEnum from typing import Optional from pydantic import BaseModel @@ -8,7 +8,7 @@ from core.model_runtime.entities.message_entities import AssistantPromptMessage, from core.model_runtime.entities.model_entities import ModelUsage, PriceInfo -class LLMMode(Enum): +class LLMMode(StrEnum): """ Enum class for large language model mode. """ diff --git a/api/core/model_runtime/model_providers/azure_ai_studio/azure_ai_studio.yaml b/api/core/model_runtime/model_providers/azure_ai_studio/azure_ai_studio.yaml index 9e17ba0884..6d9516b671 100644 --- a/api/core/model_runtime/model_providers/azure_ai_studio/azure_ai_studio.yaml +++ b/api/core/model_runtime/model_providers/azure_ai_studio/azure_ai_studio.yaml @@ -51,6 +51,40 @@ model_credential_schema: show_on: - variable: __model_type value: llm + - variable: mode + show_on: + - variable: __model_type + value: llm + label: + en_US: Completion mode + type: select + required: false + default: chat + placeholder: + zh_Hans: 选择对话类型 + en_US: Select completion mode + options: + - value: completion + label: + en_US: Completion + zh_Hans: 补全 + - value: chat + label: + en_US: Chat + zh_Hans: 对话 + - variable: context_size + label: + zh_Hans: 模型上下文长度 + en_US: Model context size + required: true + show_on: + - variable: __model_type + value: llm + type: text-input + default: "4096" + placeholder: + zh_Hans: 在此输入您的模型上下文长度 + en_US: Enter your Model context size - variable: jwt_token required: true label: diff --git a/api/core/model_runtime/model_providers/azure_ai_studio/llm/llm.py b/api/core/model_runtime/model_providers/azure_ai_studio/llm/llm.py index 393f8494dc..97c88d0756 100644 --- a/api/core/model_runtime/model_providers/azure_ai_studio/llm/llm.py +++ b/api/core/model_runtime/model_providers/azure_ai_studio/llm/llm.py @@ -20,7 +20,7 @@ from azure.core.exceptions import ( ) from core.model_runtime.callbacks.base_callback import Callback -from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage +from core.model_runtime.entities.llm_entities import LLMMode, LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage from core.model_runtime.entities.message_entities import ( AssistantPromptMessage, PromptMessage, @@ -30,6 +30,7 @@ from core.model_runtime.entities.model_entities import ( AIModelEntity, FetchFrom, I18nObject, + ModelPropertyKey, ModelType, ParameterRule, ParameterType, @@ -334,7 +335,10 @@ class AzureAIStudioLargeLanguageModel(LargeLanguageModel): fetch_from=FetchFrom.CUSTOMIZABLE_MODEL, model_type=ModelType.LLM, features=[], - model_properties={}, + model_properties={ + ModelPropertyKey.CONTEXT_SIZE: int(credentials.get("context_size", "4096")), + ModelPropertyKey.MODE: credentials.get("mode", LLMMode.CHAT), + }, parameter_rules=rules, ) diff --git a/api/core/model_runtime/model_providers/google/llm/gemini-2.0-flash-001.yml b/api/core/model_runtime/model_providers/google/llm/gemini-2.0-flash-001.yaml similarity index 100% rename from api/core/model_runtime/model_providers/google/llm/gemini-2.0-flash-001.yml rename to api/core/model_runtime/model_providers/google/llm/gemini-2.0-flash-001.yaml diff --git a/api/core/model_runtime/model_providers/ollama/llm/llm.py b/api/core/model_runtime/model_providers/ollama/llm/llm.py index 0377731175..b640914b39 100644 --- a/api/core/model_runtime/model_providers/ollama/llm/llm.py +++ b/api/core/model_runtime/model_providers/ollama/llm/llm.py @@ -314,7 +314,6 @@ class OllamaLargeLanguageModel(LargeLanguageModel): """ full_text = "" chunk_index = 0 - is_reasoning_started = False def create_final_llm_result_chunk( index: int, message: AssistantPromptMessage, finish_reason: str @@ -368,14 +367,7 @@ class OllamaLargeLanguageModel(LargeLanguageModel): # transform assistant message to prompt message text = chunk_json["response"] - if "" in text: - is_reasoning_started = True - text = text.replace("", "> 💭 ") - elif "" in text: - is_reasoning_started = False - text = text.replace("", "") + "\n\n" - elif is_reasoning_started: - text = text.replace("\n", "\n> ") + text = self._wrap_thinking_by_tag(text) assistant_prompt_message = AssistantPromptMessage(content=text) diff --git a/api/core/model_runtime/model_providers/siliconflow/llm/_position.yaml b/api/core/model_runtime/model_providers/siliconflow/llm/_position.yaml index 1ec9aee641..2da670d4df 100644 --- a/api/core/model_runtime/model_providers/siliconflow/llm/_position.yaml +++ b/api/core/model_runtime/model_providers/siliconflow/llm/_position.yaml @@ -17,6 +17,13 @@ - deepseek-ai/DeepSeek-V2.5 - deepseek-ai/DeepSeek-V3 - deepseek-ai/DeepSeek-Coder-V2-Instruct +- deepseek-ai/DeepSeek-R1-Distill-Llama-8B +- deepseek-ai/DeepSeek-R1-Distill-Llama-70B +- deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B +- deepseek-ai/DeepSeek-R1-Distill-Qwen-7B +- deepseek-ai/DeepSeek-R1-Distill-Qwen-14B +- deepseek-ai/DeepSeek-R1-Distill-Qwen-32B +- deepseek-ai/Janus-Pro-7B - THUDM/glm-4-9b-chat - 01-ai/Yi-1.5-34B-Chat-16K - 01-ai/Yi-1.5-9B-Chat-16K diff --git a/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-llama-70B.yaml b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-llama-70B.yaml new file mode 100644 index 0000000000..59e0b4d68e --- /dev/null +++ b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-llama-70B.yaml @@ -0,0 +1,21 @@ +model: deepseek-ai/DeepSeek-R1-Distill-Llama-70B +label: + zh_Hans: deepseek-ai/DeepSeek-R1-Distill-Llama-70B + en_US: deepseek-ai/DeepSeek-R1-Distill-Llama-70B +model_type: llm +features: + - agent-thought +model_properties: + mode: chat + context_size: 32000 +parameter_rules: + - name: max_tokens + use_template: max_tokens + min: 1 + max: 8192 + default: 4096 +pricing: + input: "0.00" + output: "4.3" + unit: "0.000001" + currency: RMB diff --git a/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-llama-8B.yaml b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-llama-8B.yaml new file mode 100644 index 0000000000..f3256aa5a0 --- /dev/null +++ b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-llama-8B.yaml @@ -0,0 +1,21 @@ +model: deepseek-ai/DeepSeek-R1-Distill-Llama-8B +label: + zh_Hans: deepseek-ai/DeepSeek-R1-Distill-Llama-8B + en_US: deepseek-ai/DeepSeek-R1-Distill-Llama-8B +model_type: llm +features: + - agent-thought +model_properties: + mode: chat + context_size: 32000 +parameter_rules: + - name: max_tokens + use_template: max_tokens + min: 1 + max: 8192 + default: 4096 +pricing: + input: "0.00" + output: "0.00" + unit: "0.000001" + currency: RMB diff --git a/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-1.5B.yaml b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-1.5B.yaml new file mode 100644 index 0000000000..7297278654 --- /dev/null +++ b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-1.5B.yaml @@ -0,0 +1,21 @@ +model: deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B +label: + zh_Hans: deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B + en_US: deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B +model_type: llm +features: + - agent-thought +model_properties: + mode: chat + context_size: 32000 +parameter_rules: + - name: max_tokens + use_template: max_tokens + min: 1 + max: 8192 + default: 4096 +pricing: + input: "0.00" + output: "1.26" + unit: "0.000001" + currency: RMB diff --git a/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-14B.yaml b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-14B.yaml new file mode 100644 index 0000000000..24b5c89ebf --- /dev/null +++ b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-14B.yaml @@ -0,0 +1,21 @@ +model: deepseek-ai/DeepSeek-R1-Distill-Qwen-14B +label: + zh_Hans: deepseek-ai/DeepSeek-R1-Distill-Qwen-14B + en_US: deepseek-ai/DeepSeek-R1-Distill-Qwen-14B +model_type: llm +features: + - agent-thought +model_properties: + mode: chat + context_size: 32000 +parameter_rules: + - name: max_tokens + use_template: max_tokens + min: 1 + max: 8192 + default: 4096 +pricing: + input: "0.00" + output: "0.70" + unit: "0.000001" + currency: RMB diff --git a/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-32B.yaml b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-32B.yaml new file mode 100644 index 0000000000..2a8cce1f96 --- /dev/null +++ b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-32B.yaml @@ -0,0 +1,21 @@ +model: deepseek-ai/DeepSeek-R1-Distill-Qwen-32B +label: + zh_Hans: deepseek-ai/DeepSeek-R1-Distill-Qwen-32B + en_US: deepseek-ai/DeepSeek-R1-Distill-Qwen-32B +model_type: llm +features: + - agent-thought +model_properties: + mode: chat + context_size: 32000 +parameter_rules: + - name: max_tokens + use_template: max_tokens + min: 1 + max: 8192 + default: 4096 +pricing: + input: "0.00" + output: "1.26" + unit: "0.000001" + currency: RMB diff --git a/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-7B.yaml b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-7B.yaml new file mode 100644 index 0000000000..cde1c14aae --- /dev/null +++ b/api/core/model_runtime/model_providers/siliconflow/llm/deepseek-r1-distill-qwen-7B.yaml @@ -0,0 +1,21 @@ +model: deepseek-ai/DeepSeek-R1-Distill-Qwen-7B +label: + zh_Hans: deepseek-ai/DeepSeek-R1-Distill-Qwen-7B + en_US: deepseek-ai/DeepSeek-R1-Distill-Qwen-7B +model_type: llm +features: + - agent-thought +model_properties: + mode: chat + context_size: 32000 +parameter_rules: + - name: max_tokens + use_template: max_tokens + min: 1 + max: 8192 + default: 4096 +pricing: + input: "0.00" + output: "0.00" + unit: "0.000001" + currency: RMB diff --git a/api/core/model_runtime/model_providers/siliconflow/llm/janus-pro-7B.yaml b/api/core/model_runtime/model_providers/siliconflow/llm/janus-pro-7B.yaml new file mode 100644 index 0000000000..dabbd745e5 --- /dev/null +++ b/api/core/model_runtime/model_providers/siliconflow/llm/janus-pro-7B.yaml @@ -0,0 +1,22 @@ +model: deepseek-ai/Janus-Pro-7B +label: + zh_Hans: deepseek-ai/Janus-Pro-7B + en_US: deepseek-ai/Janus-Pro-7B +model_type: llm +features: + - agent-thought + - vision +model_properties: + mode: chat + context_size: 32000 +parameter_rules: + - name: max_tokens + use_template: max_tokens + min: 1 + max: 8192 + default: 4096 +pricing: + input: "0.00" + output: "0.00" + unit: "0.000001" + currency: RMB diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0107.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0107.yaml index ef1841b517..661311f178 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0107.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0107.yaml @@ -69,6 +69,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0403.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0403.yaml index a2ea5df130..76b739a92b 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0403.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0403.yaml @@ -69,6 +69,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0428.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0428.yaml index a467665f11..334b41257f 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0428.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0428.yaml @@ -69,6 +69,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0919.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0919.yaml index 78661eaea0..bfa70ca935 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0919.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-0919.yaml @@ -69,6 +69,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-1201.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-1201.yaml index 6f4674576b..83c5732cd6 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-1201.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-1201.yaml @@ -68,6 +68,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-latest.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-latest.yaml index 8b5f005473..538bfb0448 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-latest.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-latest.yaml @@ -69,6 +69,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-longcontext.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-longcontext.yaml index cc0bb7a117..52bd758702 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-longcontext.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-max-longcontext.yaml @@ -69,6 +69,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0206.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0206.yaml index 0b1a6f81df..d37052f560 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0206.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0206.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0624.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0624.yaml index 7706005bb5..0025db9bd1 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0624.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0624.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0723.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0723.yaml index 348276fc08..401a15b690 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0723.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0723.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0806.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0806.yaml index 29f125135e..39154708a1 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0806.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0806.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0919.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0919.yaml index 905fa1e102..2ed2949a45 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0919.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-0919.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-chat.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-chat.yaml index c7a3549727..d891796bac 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-chat.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-chat.yaml @@ -69,6 +69,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-latest.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-latest.yaml index 608f52c296..7ef5c04975 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-latest.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-plus-latest.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0206.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0206.yaml index 7ee0d44f2f..09bc797465 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0206.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0206.yaml @@ -68,6 +68,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0624.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0624.yaml index 20a3f7eb64..036a96d1ae 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0624.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0624.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0919.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0919.yaml index ba73dec363..866efa3248 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0919.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-0919.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-chat.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-chat.yaml index d785b7fe85..98c78ba8ac 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-chat.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-chat.yaml @@ -69,6 +69,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-latest.yaml b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-latest.yaml index fe38a4283c..e1193aeb7f 100644 --- a/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-latest.yaml +++ b/api/core/model_runtime/model_providers/tongyi/llm/qwen-turbo-latest.yaml @@ -67,6 +67,15 @@ parameter_rules: help: zh_Hans: 用于控制模型生成时的重复度。提高repetition_penalty时可以降低模型生成的重复度。1.0表示不做惩罚。 en_US: Used to control the repeatability when generating models. Increasing repetition_penalty can reduce the duplication of model generation. 1.0 means no punishment. + - name: enable_search + type: boolean + default: false + label: + zh_Hans: 联网搜索 + en_US: Web Search + help: + zh_Hans: 模型内置了互联网搜索服务,该参数控制模型在生成文本时是否参考使用互联网搜索结果。启用互联网搜索,模型会将搜索结果作为文本生成过程中的参考信息,但模型会基于其内部逻辑“自行判断”是否使用互联网搜索结果。 + en_US: The model has a built-in Internet search service. This parameter controls whether the model refers to Internet search results when generating text. When Internet search is enabled, the model will use the search results as reference information in the text generation process, but the model will "judge" whether to use Internet search results based on its internal logic. - name: response_format use_template: response_format pricing: diff --git a/api/core/model_runtime/model_providers/xinference/llm/llm.py b/api/core/model_runtime/model_providers/xinference/llm/llm.py index 87f89ed061..fcf452d627 100644 --- a/api/core/model_runtime/model_providers/xinference/llm/llm.py +++ b/api/core/model_runtime/model_providers/xinference/llm/llm.py @@ -1,4 +1,3 @@ -import re from collections.abc import Generator, Iterator from typing import Optional, cast @@ -636,16 +635,13 @@ class XinferenceAILargeLanguageModel(LargeLanguageModel): handle stream chat generate response """ full_response = "" - is_reasoning_started_tag = False for chunk in resp: if len(chunk.choices) == 0: continue delta = chunk.choices[0] if delta.finish_reason is None and (delta.delta.content is None or delta.delta.content == ""): continue - delta_content = delta.delta.content - if not delta_content: - delta_content = "" + delta_content = delta.delta.content or "" # check if there is a tool call in the response function_call = None tool_calls = [] @@ -658,15 +654,7 @@ class XinferenceAILargeLanguageModel(LargeLanguageModel): if function_call: assistant_message_tool_calls += [self._extract_response_function_call(function_call)] - if not is_reasoning_started_tag and "" in delta_content: - is_reasoning_started_tag = True - delta_content = "> 💭 " + delta_content.replace("", "") - elif is_reasoning_started_tag and "" in delta_content: - delta_content = delta_content.replace("", "") + "\n\n" - is_reasoning_started_tag = False - elif is_reasoning_started_tag: - if "\n" in delta_content: - delta_content = re.sub(r"\n(?!(>|\n))", "\n> ", delta_content) + delta_content = self._wrap_thinking_by_tag(delta_content) # transform assistant message to prompt message assistant_prompt_message = AssistantPromptMessage( content=delta_content or "", tool_calls=assistant_message_tool_calls diff --git a/api/core/workflow/nodes/llm/entities.py b/api/core/workflow/nodes/llm/entities.py index 505068104c..bf54fdb80c 100644 --- a/api/core/workflow/nodes/llm/entities.py +++ b/api/core/workflow/nodes/llm/entities.py @@ -3,7 +3,7 @@ from typing import Any, Optional from pydantic import BaseModel, Field, field_validator -from core.model_runtime.entities import ImagePromptMessageContent +from core.model_runtime.entities import ImagePromptMessageContent, LLMMode from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate, MemoryConfig from core.workflow.entities.variable_entities import VariableSelector from core.workflow.nodes.base import BaseNodeData @@ -12,7 +12,7 @@ from core.workflow.nodes.base import BaseNodeData class ModelConfig(BaseModel): provider: str name: str - mode: str + mode: LLMMode completion_params: dict[str, Any] = {} diff --git a/api/extensions/storage/aws_s3_storage.py b/api/extensions/storage/aws_s3_storage.py index 7b6b2eedd6..ce6b194f40 100644 --- a/api/extensions/storage/aws_s3_storage.py +++ b/api/extensions/storage/aws_s3_storage.py @@ -32,7 +32,11 @@ class AwsS3Storage(BaseStorage): aws_access_key_id=dify_config.S3_ACCESS_KEY, endpoint_url=dify_config.S3_ENDPOINT, region_name=dify_config.S3_REGION, - config=Config(s3={"addressing_style": dify_config.S3_ADDRESS_STYLE}), + config=Config( + s3={"addressing_style": dify_config.S3_ADDRESS_STYLE}, + request_checksum_calculation="when_required", + response_checksum_validation="when_required", + ), ) # create bucket try: diff --git a/api/services/account_service.py b/api/services/account_service.py index dd1cc5f94f..5388e1878e 100644 --- a/api/services/account_service.py +++ b/api/services/account_service.py @@ -77,6 +77,7 @@ class AccountService: prefix="email_code_account_deletion_rate_limit", max_attempts=1, time_window=60 * 1 ) LOGIN_MAX_ERROR_LIMITS = 5 + FORGOT_PASSWORD_MAX_ERROR_LIMITS = 5 @staticmethod def _get_refresh_token_key(refresh_token: str) -> str: @@ -503,6 +504,32 @@ class AccountService: key = f"login_error_rate_limit:{email}" redis_client.delete(key) + @staticmethod + def add_forgot_password_error_rate_limit(email: str) -> None: + key = f"forgot_password_error_rate_limit:{email}" + count = redis_client.get(key) + if count is None: + count = 0 + count = int(count) + 1 + redis_client.setex(key, dify_config.FORGOT_PASSWORD_LOCKOUT_DURATION, count) + + @staticmethod + def is_forgot_password_error_rate_limit(email: str) -> bool: + key = f"forgot_password_error_rate_limit:{email}" + count = redis_client.get(key) + if count is None: + return False + + count = int(count) + if count > AccountService.FORGOT_PASSWORD_MAX_ERROR_LIMITS: + return True + return False + + @staticmethod + def reset_forgot_password_error_rate_limit(email: str): + key = f"forgot_password_error_rate_limit:{email}" + redis_client.delete(key) + @staticmethod def is_email_send_ip_limit(ip_address: str): minute_key = f"email_send_ip_limit_minute:{ip_address}" diff --git a/docker-legacy/docker-compose.yaml b/docker-legacy/docker-compose.yaml index d2b6689453..0a071e80b3 100644 --- a/docker-legacy/docker-compose.yaml +++ b/docker-legacy/docker-compose.yaml @@ -2,7 +2,7 @@ version: '3' services: # API service api: - image: langgenius/dify-api:0.15.2 + image: langgenius/dify-api:0.15.3 restart: always environment: # Startup mode, 'api' starts the API server. @@ -227,7 +227,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:0.15.2 + image: langgenius/dify-api:0.15.3 restart: always environment: CONSOLE_WEB_URL: '' @@ -397,7 +397,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:0.15.2 + image: langgenius/dify-web:0.15.3 restart: always environment: # The base URL of console application api server, refers to the Console base URL of WEB service if console domain is diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index 8aafc61888..c10c4d80d8 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.15.2 + image: langgenius/dify-api:0.15.3 restart: always environment: # Use the shared environment variables. @@ -25,7 +25,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:0.15.2 + image: langgenius/dify-api:0.15.3 restart: always environment: # Use the shared environment variables. @@ -47,7 +47,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:0.15.2 + image: langgenius/dify-web:0.15.3 restart: always environment: CONSOLE_API_URL: ${CONSOLE_API_URL:-} diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index a11ec261f3..67207fd466 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -393,7 +393,7 @@ x-shared-env: &shared-api-worker-env services: # API service api: - image: langgenius/dify-api:0.15.2 + image: langgenius/dify-api:0.15.3 restart: always environment: # Use the shared environment variables. @@ -416,7 +416,7 @@ services: # worker service # The Celery worker for processing the queue. worker: - image: langgenius/dify-api:0.15.2 + image: langgenius/dify-api:0.15.3 restart: always environment: # Use the shared environment variables. @@ -438,7 +438,7 @@ services: # Frontend web application. web: - image: langgenius/dify-web:0.15.2 + image: langgenius/dify-web:0.15.3 restart: always environment: CONSOLE_API_URL: ${CONSOLE_API_URL:-} diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx index 1d96320309..91b305dc8c 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx @@ -161,9 +161,9 @@ const AppDetailLayout: FC = (props) => { } return ( -
+
{appDetail && ( - + )}
{children} diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx index 8f3ee510b8..208078f612 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx @@ -24,9 +24,11 @@ import AppContext from '@/context/app-context' export type ICardViewProps = { appId: string + isInPanel?: boolean + className?: string } -const CardView: FC = ({ appId }) => { +const CardView: FC = ({ appId, isInPanel, className }) => { const { t } = useTranslation() const { notify } = useContext(ToastContext) const appDetail = useAppStore(state => state.appDetail) @@ -120,10 +122,11 @@ const CardView: FC = ({ appId }) => { return return ( -
+
= ({ appId }) => {
diff --git a/web/app/(commonLayout)/datasets/ApiServer.tsx b/web/app/(commonLayout)/datasets/ApiServer.tsx index 7baa342a62..0ed2663088 100644 --- a/web/app/(commonLayout)/datasets/ApiServer.tsx +++ b/web/app/(commonLayout)/datasets/ApiServer.tsx @@ -31,8 +31,6 @@ const ApiServer: FC = ({
) diff --git a/web/app/components/app-sidebar/app-info.tsx b/web/app/components/app-sidebar/app-info.tsx index 12f9c59cd1..57eb013be7 100644 --- a/web/app/components/app-sidebar/app-info.tsx +++ b/web/app/components/app-sidebar/app-info.tsx @@ -1,18 +1,18 @@ import { useTranslation } from 'react-i18next' import { useRouter } from 'next/navigation' import { useContext, useContextSelector } from 'use-context-selector' -import { RiArrowDownSLine } from '@remixicon/react' import React, { useCallback, useState } from 'react' +import { + RiDeleteBinLine, + RiEditLine, + RiEqualizer2Line, + RiFileCopy2Line, + RiFileDownloadLine, + RiFileUploadLine, +} from '@remixicon/react' import AppIcon from '../base/app-icon' import SwitchAppModal from '../app/switch-app-modal' -import s from './style.module.css' import cn from '@/utils/classnames' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' -import Divider from '@/app/components/base/divider' import Confirm from '@/app/components/base/confirm' import { useStore as useAppStore } from '@/app/components/app/store' import { ToastContext } from '@/app/components/base/toast' @@ -22,8 +22,6 @@ import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/ap import DuplicateAppModal from '@/app/components/app/duplicate-modal' import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal' import CreateAppModal from '@/app/components/explore/create-app-modal' -import { AiText, ChatBot, CuteRobot } from '@/app/components/base/icons/src/vender/solid/communication' -import { Route } from '@/app/components/base/icons/src/vender/solid/mapsAndTravel' import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { getRedirection } from '@/utils/app-redirection' @@ -31,6 +29,9 @@ import UpdateDSLModal from '@/app/components/workflow/update-dsl-modal' import type { EnvironmentVariable } from '@/app/components/workflow/types' import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal' import { fetchWorkflowDraft } from '@/service/workflow' +import ContentDialog from '@/app/components/base/content-dialog' +import Button from '@/app/components/base/button' +import CardView from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView' export type IAppInfoProps = { expand: boolean @@ -47,7 +48,6 @@ const AppInfo = ({ expand }: IAppInfoProps) => { const [showEditModal, setShowEditModal] = useState(false) const [showDuplicateModal, setShowDuplicateModal] = useState(false) const [showConfirmDelete, setShowConfirmDelete] = useState(false) - const [showSwitchTip, setShowSwitchTip] = useState('') const [showSwitchModal, setShowSwitchModal] = useState(false) const [showImportDSLModal, setShowImportDSLModal] = useState(false) const [secretEnvList, setSecretEnvList] = useState([]) @@ -183,291 +183,199 @@ const AppInfo = ({ expand }: IAppInfoProps) => { return null return ( - -
- { - if (isCurrentWorkspaceEditor) - setOpen(v => !v) - }} - className='block' - > -
-
- - - {appDetail.mode === 'advanced-chat' && ( - - )} - {appDetail.mode === 'agent-chat' && ( - - )} - {appDetail.mode === 'chat' && ( - - )} - {appDetail.mode === 'completion' && ( - - )} - {appDetail.mode === 'workflow' && ( - - )} - -
- {expand && ( -
-
-
{appDetail.name}
- {isCurrentWorkspaceEditor && } -
-
- {appDetail.mode === 'advanced-chat' && ( - <> -
{t('app.types.chatbot').toUpperCase()}
-
{t('app.types.advanced').toUpperCase()}
- - )} - {appDetail.mode === 'agent-chat' && ( -
{t('app.types.agent').toUpperCase()}
- )} - {appDetail.mode === 'chat' && ( - <> -
{t('app.types.chatbot').toUpperCase()}
-
{(t('app.types.basic').toUpperCase())}
- - )} - {appDetail.mode === 'completion' && ( - <> -
{t('app.types.completion').toUpperCase()}
-
{(t('app.types.basic').toUpperCase())}
- - )} - {appDetail.mode === 'workflow' && ( -
{t('app.types.workflow').toUpperCase()}
- )} -
+
+ + setOpen(false)} + className='!p-0 flex flex-col absolute left-2 top-2 bottom-2 w-[420px] rounded-2xl' + > +
+
+ +
+
{appDetail.name}
+
{appDetail.mode === 'advanced-chat' ? t('app.types.chatbot') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}
- {/* description */} - {appDetail.description && ( -
{appDetail.description}
- )} - {/* operations */} - -
-
{ +
+ {/* description */} + {appDetail.description && ( +
{appDetail.description}
+ )} + {/* operations */} +
+
-
{ + }} + > + + {t('app.editApp')} + +
- {(appDetail.mode === 'completion' || appDetail.mode === 'chat') && ( - <> - -
setShowSwitchTip(appDetail.mode)} - onMouseLeave={() => setShowSwitchTip('')} - onClick={() => { - setOpen(false) - setShowSwitchModal(true) - }} - > - {t('app.switch')} -
- - )} - -
- {t('app.export')} -
- { - (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow') && ( -
{ - setOpen(false) - setShowImportDSLModal(true) - }}> - {t('workflow.common.importDSL')} -
- ) - } - -
{ - setOpen(false) - setShowConfirmDelete(true) - }}> - - {t('common.operation.delete')} - -
-
- {/* switch tip */} -
-
-
-
- {showSwitchTip === 'chat' ? t('app.types.advanced') : t('app.types.workflow')} - BETA -
-
{t('app.newApp.advancedFor').toLocaleUpperCase()}
-
{t('app.newApp.advancedDescription')}
-
-
+ + {t('app.duplicate')} + + + { + (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow') && ( + + ) + }
- - {showSwitchModal && ( - setShowSwitchModal(false)} - onSuccess={() => setShowSwitchModal(false)} +
+
+ - )} - {showEditModal && ( - setShowEditModal(false)} - /> - )} - {showDuplicateModal && ( - setShowDuplicateModal(false)} - /> - )} - {showConfirmDelete && ( - setShowConfirmDelete(false)} - /> - )} - {showImportDSLModal && ( - setShowImportDSLModal(false)} - onBackup={exportCheck} - /> - )} - {secretEnvList.length > 0 && ( - setSecretEnvList([])} - /> - )} -
- +
+
+ +
+
+ {showSwitchModal && ( + setShowSwitchModal(false)} + onSuccess={() => setShowSwitchModal(false)} + /> + )} + {showEditModal && ( + setShowEditModal(false)} + /> + )} + {showDuplicateModal && ( + setShowDuplicateModal(false)} + /> + )} + {showConfirmDelete && ( + setShowConfirmDelete(false)} + /> + )} + {showImportDSLModal && ( + setShowImportDSLModal(false)} + onBackup={exportCheck} + /> + )} + {secretEnvList.length > 0 && ( + setSecretEnvList([])} + /> + )} +
) } diff --git a/web/app/components/app-sidebar/basic.tsx b/web/app/components/app-sidebar/basic.tsx index 51fc10721e..6600920ba7 100644 --- a/web/app/components/app-sidebar/basic.tsx +++ b/web/app/components/app-sidebar/basic.tsx @@ -58,7 +58,7 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type const { t } = useTranslation() return ( -
+
{icon && icon_background && iconType === 'app' && (
@@ -71,8 +71,10 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type } {mode === 'expand' &&
-
- {name} +
+
+ {name} +
{hoverTip && }
-
{type}
{isExternal ? t('dataset.externalTag') : ''}
}
diff --git a/web/app/components/app-sidebar/index.tsx b/web/app/components/app-sidebar/index.tsx index 61e4bf8330..dec8499eb5 100644 --- a/web/app/components/app-sidebar/index.tsx +++ b/web/app/components/app-sidebar/index.tsx @@ -57,7 +57,7 @@ const AppDetailNav = ({ title, desc, isExternal, icon, icon_background, navigati
{iconType === 'app' && ( diff --git a/web/app/components/app/overview/appCard.tsx b/web/app/components/app/overview/appCard.tsx index f9f5c1fbff..72b9671f2d 100644 --- a/web/app/components/app/overview/appCard.tsx +++ b/web/app/components/app/overview/appCard.tsx @@ -1,14 +1,14 @@ 'use client' -import type { HTMLProps } from 'react' import React, { useMemo, useState } from 'react' -import { - Cog8ToothIcon, - DocumentTextIcon, - PaintBrushIcon, - RocketLaunchIcon, -} from '@heroicons/react/24/outline' import { usePathname, useRouter } from 'next/navigation' import { useTranslation } from 'react-i18next' +import { + RiBookOpenLine, + RiEqualizer2Line, + RiExternalLinkLine, + RiPaintBrushLine, + RiWindowLine, +} from '@remixicon/react' import SettingsModal from './settings' import EmbeddedModal from './embedded' import CustomizeModal from './customize' @@ -18,7 +18,6 @@ import Tooltip from '@/app/components/base/tooltip' import AppBasic from '@/app/components/app-sidebar/basic' import { asyncRunSafe, randomString } from '@/utils' import Button from '@/app/components/base/button' -import Tag from '@/app/components/base/tag' import Switch from '@/app/components/base/switch' import Divider from '@/app/components/base/divider' import CopyFeedback from '@/app/components/base/copy-feedback' @@ -28,10 +27,12 @@ import SecretKeyButton from '@/app/components/develop/secret-key/secret-key-butt import type { AppDetailResponse } from '@/models/app' import { useAppContext } from '@/context/app-context' import type { AppSSO } from '@/types/app' +import Indicator from '@/app/components/header/indicator' export type IAppCardProps = { className?: string appInfo: AppDetailResponse & Partial + isInPanel?: boolean cardType?: 'api' | 'webapp' customBgColor?: string onChangeStatus: (val: boolean) => Promise @@ -39,12 +40,9 @@ export type IAppCardProps = { onGenerateCode?: () => Promise } -const EmbedIcon = ({ className = '' }: HTMLProps) => { - return
-} - function AppCard({ appInfo, + isInPanel, cardType = 'webapp', customBgColor, onChangeStatus, @@ -66,17 +64,18 @@ function AppCard({ const OPERATIONS_MAP = useMemo(() => { const operationsMap = { webapp: [ - { opName: t('appOverview.overview.appInfo.preview'), opIcon: RocketLaunchIcon }, - { opName: t('appOverview.overview.appInfo.customize.entry'), opIcon: PaintBrushIcon }, + { opName: t('appOverview.overview.appInfo.launch'), opIcon: RiExternalLinkLine }, ] as { opName: string; opIcon: any }[], - api: [{ opName: t('appOverview.overview.apiInfo.doc'), opIcon: DocumentTextIcon }], + api: [{ opName: t('appOverview.overview.apiInfo.doc'), opIcon: RiBookOpenLine }], app: [], } if (appInfo.mode !== 'completion' && appInfo.mode !== 'workflow') - operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.embedded.entry'), opIcon: EmbedIcon }) + operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.embedded.entry'), opIcon: RiWindowLine }) + + operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.customize.entry'), opIcon: RiPaintBrushLine }) if (isCurrentWorkspaceEditor) - operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.settings.entry'), opIcon: Cog8ToothIcon }) + operationsMap.webapp.push({ opName: t('appOverview.overview.appInfo.settings.entry'), opIcon: RiEqualizer2Line }) return operationsMap }, [isCurrentWorkspaceEditor, appInfo, t]) @@ -92,13 +91,9 @@ function AppCard({ const appUrl = `${app_base_url}/${appMode}/${access_token}` const apiUrl = appInfo?.api_base_url - let bgColor = 'bg-primary-50 bg-opacity-40' - if (cardType === 'api') - bgColor = 'bg-purple-50' - const genClickFuncByName = (opName: string) => { switch (opName) { - case t('appOverview.overview.appInfo.preview'): + case t('appOverview.overview.appInfo.launch'): return () => { window.open(appUrl, '_blank') } @@ -135,49 +130,50 @@ function AppCard({ return (
-
-
- -
- - {runningStatus - ? t('appOverview.overview.status.running') - : t('appOverview.overview.status.disable')} - +
+
+
+ +
+ +
+ {runningStatus + ? t('appOverview.overview.status.running') + : t('appOverview.overview.status.disable')} +
+
-
-
-
-
+
+
{isApp ? t('appOverview.overview.appInfo.accessibleAddress') : t('appOverview.overview.apiInfo.accessibleAddress')}
-
-
-
+
+
+
{isApp ? appUrl : apiUrl}
- - {isApp && } + {isApp && } + {isApp && } {/* button copy link/ button regenerate */} {showConfirmDelete && (
setShowConfirmDelete(true)} >
-
- {!isApp && } +
+ {!isApp && } {OPERATIONS_MAP[cardType].map((op) => { const disabled = op.opName === t('appOverview.overview.appInfo.settings.entry') @@ -219,7 +215,9 @@ function AppCard({ : !runningStatus return ( diff --git a/web/app/components/base/content-dialog/index.tsx b/web/app/components/base/content-dialog/index.tsx new file mode 100644 index 0000000000..9e6726b1f6 --- /dev/null +++ b/web/app/components/base/content-dialog/index.tsx @@ -0,0 +1,59 @@ +import { Fragment, type ReactNode } from 'react' +import { Transition } from '@headlessui/react' +import classNames from '@/utils/classnames' + +type ContentDialogProps = { + className?: string + show: boolean + onClose?: () => void + children: ReactNode +} + +const ContentDialog = ({ + className, + show, + onClose, + children, +}: ContentDialogProps) => { + return ( + + +
+ + + +
+ {children} +
+
+ + ) +} + +export default ContentDialog diff --git a/web/app/components/base/copy-feedback/index.tsx b/web/app/components/base/copy-feedback/index.tsx index ead1eb1d18..ec6b6ddb31 100644 --- a/web/app/components/base/copy-feedback/index.tsx +++ b/web/app/components/base/copy-feedback/index.tsx @@ -35,7 +35,7 @@ const CopyFeedback = ({ content, className }: Props) => { } >
diff --git a/web/app/components/base/qrcode/index.tsx b/web/app/components/base/qrcode/index.tsx index c9323992e9..75d4831db7 100644 --- a/web/app/components/base/qrcode/index.tsx +++ b/web/app/components/base/qrcode/index.tsx @@ -1,7 +1,7 @@ 'use client' import React, { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import QRCode from 'qrcode.react' +import { QRCodeSVG } from 'qrcode.react' import QrcodeStyle from './style.module.css' import Tooltip from '@/app/components/base/tooltip' @@ -54,20 +54,20 @@ const ShareQRCode = ({ content, selectorId, className }: Props) => { popupContent={t(`${prefixEmbedded}`) || ''} >
{isShow && (
- +
-
{t('appOverview.overview.appInfo.qrcode.scan')}
-
·
+
{t('appOverview.overview.appInfo.qrcode.scan')}
+
·
{t('appOverview.overview.appInfo.qrcode.download')}
diff --git a/web/app/components/develop/secret-key/secret-key-button.tsx b/web/app/components/develop/secret-key/secret-key-button.tsx index dab319bab4..e1845330ae 100644 --- a/web/app/components/develop/secret-key/secret-key-button.tsx +++ b/web/app/components/develop/secret-key/secret-key-button.tsx @@ -1,29 +1,31 @@ 'use client' import { useState } from 'react' import { useTranslation } from 'react-i18next' +import { RiKey2Line } from '@remixicon/react' import Button from '@/app/components/base/button' import SecretKeyModal from '@/app/components/develop/secret-key/secret-key-modal' -// import { KeyIcon } from '@heroicons/react/20/solid' type ISecretKeyButtonProps = { className?: string appId?: string - iconCls?: string textCls?: string } -const SecretKeyButton = ({ className, appId, iconCls, textCls }: ISecretKeyButtonProps) => { +const SecretKeyButton = ({ className, appId, textCls }: ISecretKeyButtonProps) => { const [isVisible, setVisible] = useState(false) const { t } = useTranslation() return ( <> - setVisible(false)} appId={appId} /> diff --git a/web/i18n/de-DE/app-overview.ts b/web/i18n/de-DE/app-overview.ts index 7cc82dd38a..018925720f 100644 --- a/web/i18n/de-DE/app-overview.ts +++ b/web/i18n/de-DE/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Dokumentation', }, }, + launch: 'Abschießen', }, apiInfo: { title: 'Backend-Service-API', diff --git a/web/i18n/de-DE/common.ts b/web/i18n/de-DE/common.ts index 915fc2a277..782d80330b 100644 --- a/web/i18n/de-DE/common.ts +++ b/web/i18n/de-DE/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Senden', skip: 'Schiff', imageCopied: 'Kopiertes Bild', + deleteApp: 'App löschen', }, placeholder: { input: 'Bitte eingeben', diff --git a/web/i18n/en-US/app-overview.ts b/web/i18n/en-US/app-overview.ts index 15801d1504..565805a271 100644 --- a/web/i18n/en-US/app-overview.ts +++ b/web/i18n/en-US/app-overview.ts @@ -33,6 +33,7 @@ const translation = { explanation: 'Ready-to-use AI WebApp', accessibleAddress: 'Public URL', preview: 'Preview', + launch: 'Launch', regenerate: 'Regenerate', regenerateNotice: 'Do you want to regenerate the public URL?', preUseReminder: 'Please enable WebApp before continuing.', diff --git a/web/i18n/en-US/common.ts b/web/i18n/en-US/common.ts index c116e080b4..018401aa56 100644 --- a/web/i18n/en-US/common.ts +++ b/web/i18n/en-US/common.ts @@ -27,6 +27,7 @@ const translation = { sure: 'I\'m sure', download: 'Download', delete: 'Delete', + deleteApp: 'Delete App', settings: 'Settings', setup: 'Setup', getForFree: 'Get for free', diff --git a/web/i18n/es-ES/app-overview.ts b/web/i18n/es-ES/app-overview.ts index 4b2769ca29..62be19f6d8 100644 --- a/web/i18n/es-ES/app-overview.ts +++ b/web/i18n/es-ES/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Documentación', }, }, + launch: 'Lanzar', }, apiInfo: { title: 'API del servicio backend', diff --git a/web/i18n/es-ES/common.ts b/web/i18n/es-ES/common.ts index 936da90200..469acd73b0 100644 --- a/web/i18n/es-ES/common.ts +++ b/web/i18n/es-ES/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Enviar', skip: 'Navío', imageCopied: 'Imagen copiada', + deleteApp: 'Eliminar aplicación', }, errorMsg: { fieldRequired: '{{field}} es requerido', diff --git a/web/i18n/fa-IR/app-overview.ts b/web/i18n/fa-IR/app-overview.ts index 6386362a54..018336cb2a 100644 --- a/web/i18n/fa-IR/app-overview.ts +++ b/web/i18n/fa-IR/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'مستندات', }, }, + launch: 'راه اندازی', }, apiInfo: { title: 'API سرویس بک‌اند', diff --git a/web/i18n/fa-IR/common.ts b/web/i18n/fa-IR/common.ts index 53086071aa..fb8cad28c2 100644 --- a/web/i18n/fa-IR/common.ts +++ b/web/i18n/fa-IR/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'ارسال', skip: 'کشتی', imageCopied: 'تصویر کپی شده', + deleteApp: 'حذف برنامه', }, errorMsg: { fieldRequired: '{{field}} الزامی است', diff --git a/web/i18n/fr-FR/app-overview.ts b/web/i18n/fr-FR/app-overview.ts index dfc87379d8..5252bb86b5 100644 --- a/web/i18n/fr-FR/app-overview.ts +++ b/web/i18n/fr-FR/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Documentation', }, }, + launch: 'Lancer', }, apiInfo: { title: 'API de service Backend', diff --git a/web/i18n/fr-FR/common.ts b/web/i18n/fr-FR/common.ts index 662f53ab66..2d6c68e04b 100644 --- a/web/i18n/fr-FR/common.ts +++ b/web/i18n/fr-FR/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Envoyer', skip: 'Bateau', imageCopied: 'Image copied', + deleteApp: 'Supprimer l’application', }, placeholder: { input: 'Veuillez entrer', diff --git a/web/i18n/hi-IN/app-overview.ts b/web/i18n/hi-IN/app-overview.ts index d7de14c6c6..c8848d6331 100644 --- a/web/i18n/hi-IN/app-overview.ts +++ b/web/i18n/hi-IN/app-overview.ts @@ -123,6 +123,7 @@ const translation = { operation: 'प्रलेखन', }, }, + launch: 'लॉन्च', }, apiInfo: { title: 'बैकएंड सेवा एपीआई', diff --git a/web/i18n/hi-IN/common.ts b/web/i18n/hi-IN/common.ts index 2a14cd0279..bd87012944 100644 --- a/web/i18n/hi-IN/common.ts +++ b/web/i18n/hi-IN/common.ts @@ -50,6 +50,7 @@ const translation = { skip: 'जहाज़', submit: 'जमा करें', imageCopied: 'कॉपी की गई छवि', + deleteApp: 'ऐप हटाएं', }, errorMsg: { fieldRequired: '{{field}} आवश्यक है', diff --git a/web/i18n/it-IT/app-overview.ts b/web/i18n/it-IT/app-overview.ts index 7e4dce194b..8021bb1976 100644 --- a/web/i18n/it-IT/app-overview.ts +++ b/web/i18n/it-IT/app-overview.ts @@ -125,6 +125,7 @@ const translation = { operation: 'Documentazione', }, }, + launch: 'Lanciare', }, apiInfo: { title: 'API del servizio backend', diff --git a/web/i18n/it-IT/common.ts b/web/i18n/it-IT/common.ts index c764a93dac..1a30229fb7 100644 --- a/web/i18n/it-IT/common.ts +++ b/web/i18n/it-IT/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Invia', skip: 'Nave', imageCopied: 'Immagine copiata', + deleteApp: 'Elimina app', }, errorMsg: { fieldRequired: '{{field}} è obbligatorio', diff --git a/web/i18n/ja-JP/app-overview.ts b/web/i18n/ja-JP/app-overview.ts index 0895d691c3..7e750a4775 100644 --- a/web/i18n/ja-JP/app-overview.ts +++ b/web/i18n/ja-JP/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'ドキュメント', }, }, + launch: '発射', }, apiInfo: { title: 'バックエンドサービスAPI', diff --git a/web/i18n/ja-JP/common.ts b/web/i18n/ja-JP/common.ts index e176f5d139..87ed2afc94 100644 --- a/web/i18n/ja-JP/common.ts +++ b/web/i18n/ja-JP/common.ts @@ -50,6 +50,7 @@ const translation = { submit: '送信', skip: 'スキップ', imageCopied: 'コピーした画像', + deleteApp: 'アプリを削除', }, errorMsg: { fieldRequired: '{{field}}は必要です', diff --git a/web/i18n/ko-KR/app-overview.ts b/web/i18n/ko-KR/app-overview.ts index 0acec73c44..775818909a 100644 --- a/web/i18n/ko-KR/app-overview.ts +++ b/web/i18n/ko-KR/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: '문서', }, }, + launch: '발사', }, apiInfo: { title: '백엔드 서비스 API', diff --git a/web/i18n/ko-KR/common.ts b/web/i18n/ko-KR/common.ts index a11af1ba31..fcdd93c78e 100644 --- a/web/i18n/ko-KR/common.ts +++ b/web/i18n/ko-KR/common.ts @@ -50,6 +50,7 @@ const translation = { submit: '전송', skip: '배', imageCopied: '복사된 이미지', + deleteApp: '앱 삭제', }, placeholder: { input: '입력해주세요', diff --git a/web/i18n/pl-PL/app-overview.ts b/web/i18n/pl-PL/app-overview.ts index 7e25b014a0..7726927565 100644 --- a/web/i18n/pl-PL/app-overview.ts +++ b/web/i18n/pl-PL/app-overview.ts @@ -123,6 +123,7 @@ const translation = { operation: 'Dokumentacja', }, }, + launch: 'Uruchomić', }, apiInfo: { title: 'API usługi w tle', diff --git a/web/i18n/pl-PL/common.ts b/web/i18n/pl-PL/common.ts index d6502416c3..5f31e5bfad 100644 --- a/web/i18n/pl-PL/common.ts +++ b/web/i18n/pl-PL/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Prześlij', skip: 'Statek', imageCopied: 'Skopiowany obraz', + deleteApp: 'Usuń aplikację', }, placeholder: { input: 'Proszę wprowadzić', diff --git a/web/i18n/pt-BR/app-overview.ts b/web/i18n/pt-BR/app-overview.ts index 1431fa13ce..a23163fc89 100644 --- a/web/i18n/pt-BR/app-overview.ts +++ b/web/i18n/pt-BR/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Documentação', }, }, + launch: 'Lançar', }, apiInfo: { title: 'API de Serviço de Back-end', diff --git a/web/i18n/pt-BR/common.ts b/web/i18n/pt-BR/common.ts index d0327de642..42e606deb3 100644 --- a/web/i18n/pt-BR/common.ts +++ b/web/i18n/pt-BR/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Enviar', skip: 'Navio', imageCopied: 'Imagem copiada', + deleteApp: 'Excluir aplicativo', }, placeholder: { input: 'Por favor, insira', diff --git a/web/i18n/ro-RO/app-overview.ts b/web/i18n/ro-RO/app-overview.ts index 07f28425e2..a5dee76508 100644 --- a/web/i18n/ro-RO/app-overview.ts +++ b/web/i18n/ro-RO/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Documentație', }, }, + launch: 'Lansa', }, apiInfo: { title: 'API serviciu backend', diff --git a/web/i18n/ro-RO/common.ts b/web/i18n/ro-RO/common.ts index 8f0cbc64cb..e7e573fba6 100644 --- a/web/i18n/ro-RO/common.ts +++ b/web/i18n/ro-RO/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Prezinte', skip: 'Navă', imageCopied: 'Imagine copiată', + deleteApp: 'Ștergeți aplicația', }, placeholder: { input: 'Vă rugăm să introduceți', diff --git a/web/i18n/ru-RU/app-overview.ts b/web/i18n/ru-RU/app-overview.ts index c26c1d5ec6..7de8a47526 100644 --- a/web/i18n/ru-RU/app-overview.ts +++ b/web/i18n/ru-RU/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Документация', }, }, + launch: 'Баркас', }, apiInfo: { title: 'API серверной части', diff --git a/web/i18n/ru-RU/common.ts b/web/i18n/ru-RU/common.ts index 2d8535e6a0..bad5c99c65 100644 --- a/web/i18n/ru-RU/common.ts +++ b/web/i18n/ru-RU/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Отправить', skip: 'Корабль', imageCopied: 'Скопированное изображение', + deleteApp: 'Удалить приложение', }, errorMsg: { fieldRequired: '{{field}} обязательно', diff --git a/web/i18n/sl-SI/app-overview.ts b/web/i18n/sl-SI/app-overview.ts index 458a5c4245..94fb788a94 100644 --- a/web/i18n/sl-SI/app-overview.ts +++ b/web/i18n/sl-SI/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Dokumentacija', }, }, + launch: 'Začetek', }, apiInfo: { title: 'API storitev v ozadju', diff --git a/web/i18n/sl-SI/common.ts b/web/i18n/sl-SI/common.ts index 2d30e0b76c..5b7d79b6fd 100644 --- a/web/i18n/sl-SI/common.ts +++ b/web/i18n/sl-SI/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Predložiti', skip: 'Ladja', imageCopied: 'Kopirana slika', + deleteApp: 'Izbriši aplikacijo', }, errorMsg: { fieldRequired: '{{field}} je obvezno', diff --git a/web/i18n/th-TH/app-overview.ts b/web/i18n/th-TH/app-overview.ts index e8bc0a64a4..27792e16c9 100644 --- a/web/i18n/th-TH/app-overview.ts +++ b/web/i18n/th-TH/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'เอกสาร', }, }, + launch: 'เรือยนต์', }, apiInfo: { title: 'API บริการแบ็กเอนด์', diff --git a/web/i18n/th-TH/common.ts b/web/i18n/th-TH/common.ts index ab6def82c5..e510c8e009 100644 --- a/web/i18n/th-TH/common.ts +++ b/web/i18n/th-TH/common.ts @@ -50,6 +50,7 @@ const translation = { skip: 'เรือ', submit: 'ส่ง', imageCopied: 'ภาพที่คัดลอก', + deleteApp: 'ลบแอพ', }, errorMsg: { fieldRequired: '{{field}} เป็นสิ่งจําเป็น', diff --git a/web/i18n/tr-TR/app-overview.ts b/web/i18n/tr-TR/app-overview.ts index 14a057a723..0b4311ae45 100644 --- a/web/i18n/tr-TR/app-overview.ts +++ b/web/i18n/tr-TR/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Dokümantasyon', }, }, + launch: 'Başlat', }, apiInfo: { title: 'Arka Uç Servis API\'si', diff --git a/web/i18n/tr-TR/common.ts b/web/i18n/tr-TR/common.ts index ea764ebd29..35c40ca475 100644 --- a/web/i18n/tr-TR/common.ts +++ b/web/i18n/tr-TR/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Gönder', skip: 'Gemi', imageCopied: 'Kopyalanan görüntü', + deleteApp: 'Uygulamayı Sil', }, errorMsg: { fieldRequired: '{{field}} gereklidir', diff --git a/web/i18n/uk-UA/app-overview.ts b/web/i18n/uk-UA/app-overview.ts index 97b3569340..e6a1485480 100644 --- a/web/i18n/uk-UA/app-overview.ts +++ b/web/i18n/uk-UA/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Документація', }, }, + launch: 'Запуску', }, apiInfo: { title: 'API сервісу Backend', diff --git a/web/i18n/uk-UA/common.ts b/web/i18n/uk-UA/common.ts index bfdaf7c7ca..318b8e2fdd 100644 --- a/web/i18n/uk-UA/common.ts +++ b/web/i18n/uk-UA/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Представити', skip: 'Корабель', imageCopied: 'Скопійоване зображення', + deleteApp: 'Видалити програму', }, placeholder: { input: 'Будь ласка, введіть текст', diff --git a/web/i18n/vi-VN/app-overview.ts b/web/i18n/vi-VN/app-overview.ts index 3d86652d9e..5f060c869a 100644 --- a/web/i18n/vi-VN/app-overview.ts +++ b/web/i18n/vi-VN/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: 'Tài liệu', }, }, + launch: 'Phóng', }, apiInfo: { title: 'API dịch vụ backend', diff --git a/web/i18n/vi-VN/common.ts b/web/i18n/vi-VN/common.ts index 9fd1af1d44..1fbe8ac832 100644 --- a/web/i18n/vi-VN/common.ts +++ b/web/i18n/vi-VN/common.ts @@ -50,6 +50,7 @@ const translation = { submit: 'Trình', skip: 'Tàu', imageCopied: 'Hình ảnh sao chép', + deleteApp: 'Xóa ứng dụng', }, placeholder: { input: 'Vui lòng nhập', diff --git a/web/i18n/zh-Hans/app-overview.ts b/web/i18n/zh-Hans/app-overview.ts index a337058d07..6274a64f13 100644 --- a/web/i18n/zh-Hans/app-overview.ts +++ b/web/i18n/zh-Hans/app-overview.ts @@ -33,6 +33,7 @@ const translation = { explanation: '开箱即用的 AI WebApp', accessibleAddress: '公开访问 URL', preview: '预览', + launch: '启动', regenerate: '重新生成', regenerateNotice: '您是否要重新生成公开访问 URL?', preUseReminder: '使用前请先打开开关', diff --git a/web/i18n/zh-Hans/common.ts b/web/i18n/zh-Hans/common.ts index 53c5337cab..5ce1cb1385 100644 --- a/web/i18n/zh-Hans/common.ts +++ b/web/i18n/zh-Hans/common.ts @@ -27,6 +27,7 @@ const translation = { sure: '我确定', download: '下载', delete: '删除', + deleteApp: '删除应用', settings: '设置', setup: '设置', getForFree: '免费获取', diff --git a/web/i18n/zh-Hant/app-overview.ts b/web/i18n/zh-Hant/app-overview.ts index f60b3b7ace..956fa9a1c9 100644 --- a/web/i18n/zh-Hant/app-overview.ts +++ b/web/i18n/zh-Hant/app-overview.ts @@ -112,6 +112,7 @@ const translation = { operation: '檢視文件', }, }, + launch: '發射', }, apiInfo: { title: '後端服務 API', diff --git a/web/i18n/zh-Hant/common.ts b/web/i18n/zh-Hant/common.ts index 735af54a89..a402db6a3a 100644 --- a/web/i18n/zh-Hant/common.ts +++ b/web/i18n/zh-Hant/common.ts @@ -50,6 +50,7 @@ const translation = { submit: '提交', skip: '船', imageCopied: '複製的圖片', + deleteApp: '刪除應用程式', }, placeholder: { input: '請輸入', diff --git a/web/package.json b/web/package.json index 952fac4a5f..bd98a14337 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "dify-web", - "version": "0.15.2", + "version": "0.15.3", "private": true, "engines": { "node": ">=18.17.0" diff --git a/web/tailwind.config.js b/web/tailwind.config.js index ad1e509b35..4cea03e851 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -99,6 +99,8 @@ const config = { 'chatbot-bg': 'var(--color-chatbot-bg)', 'chat-bubble-bg': 'var(--color-chat-bubble-bg)', 'workflow-process-bg': 'var(--color-workflow-process-bg)', + 'app-detail-bg': 'var(--color-app-detail-bg)', + 'app-detail-overlay-bg': 'var(--color-app-detail-overlay-bg)', 'dataset-chunk-process-success-bg': 'var(--color-dataset-chunk-process-success-bg)', 'dataset-chunk-process-error-bg': 'var(--color-dataset-chunk-process-error-bg)', 'dataset-chunk-detail-card-hover-bg': 'var(--color-dataset-chunk-detail-card-hover-bg)', diff --git a/web/themes/manual-dark.css b/web/themes/manual-dark.css index 9ca4cd520c..b7b410c170 100644 --- a/web/themes/manual-dark.css +++ b/web/themes/manual-dark.css @@ -19,6 +19,17 @@ html[data-theme="dark"] { rgba(34, 34, 37, 0.9) -0.1%, rgba(29, 29, 32, 0.9) 98.26% ); + --color-app-detail-bg: linear-gradient( + 169deg, + #1D1D20 1.18%, + #222225 99.52% + ); + --color-app-detail-overlay-bg: linear-gradient( + 270deg, + rgba(0, 0, 0, 0.00) 0%, + rgba(24, 24, 27, 0.02) 8%, + rgba(24, 24, 27, 0.54) 100% + ); --color-dataset-chunk-process-success-bg: linear-gradient(92deg, rgba(23, 178, 106, 0.30) 0%, rgba(0, 0, 0, 0.00) 100%); --color-dataset-chunk-process-error-bg: linear-gradient(92deg, rgba(240, 68, 56, 0.30) 0%, rgba(0, 0, 0, 0.00) 100%); --color-dataset-chunk-detail-card-hover-bg: linear-gradient(180deg, #1D1D20 0%, #222225 100%); diff --git a/web/themes/manual-light.css b/web/themes/manual-light.css index 107c869e6d..6ee2d81b3b 100644 --- a/web/themes/manual-light.css +++ b/web/themes/manual-light.css @@ -19,6 +19,17 @@ html[data-theme="light"] { rgba(249, 250, 251, 0.9) -0.1%, rgba(242, 244, 247, 0.9) 98.26% ); + --color-app-detail-bg: linear-gradient( + 169deg, + #F2F4F7 1.18%, + #F9FAFB 99.52% + ); + --color-app-detail-overlay-bg: linear-gradient( + 270deg, + rgba(0, 0, 0, 0.00) 0%, + rgba(16, 24, 40, 0.01) 8%, + rgba(16, 24, 40, 0.18) 100% + ); --color-dataset-chunk-process-success-bg: linear-gradient(92deg, rgba(23, 178, 106, 0.25) 0%, rgba(255, 255, 255, 0.00) 100%); --color-dataset-chunk-process-error-bg: linear-gradient(92deg, rgba(240, 68, 56, 0.25) 0%, rgba(255, 255, 255, 0.00) 100%); --color-dataset-chunk-detail-card-hover-bg: linear-gradient(180deg, #F2F4F7 0%, #F9FAFB 100%);