From cd0a05f114debb47c9c5e2c621543a8225033d64 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 01:57:55 +0800 Subject: [PATCH 01/73] tests: Removes outdated marketplace download test (#20454) Signed-off-by: -LAN- --- api/tests/unit_tests/core/helper/test_marketplace.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 api/tests/unit_tests/core/helper/test_marketplace.py diff --git a/api/tests/unit_tests/core/helper/test_marketplace.py b/api/tests/unit_tests/core/helper/test_marketplace.py deleted file mode 100644 index 6ccce7ac9f..0000000000 --- a/api/tests/unit_tests/core/helper/test_marketplace.py +++ /dev/null @@ -1,7 +0,0 @@ -from core.helper.marketplace import download_plugin_pkg - - -def test_download_plugin_pkg(): - pkg = download_plugin_pkg("langgenius/bing:0.0.1@e58735424d2104f208c2bd683c5142e0332045b425927067acf432b26f3d970b") - assert pkg is not None - assert len(pkg) > 0 From 482e50aae9e909f85abf1f7590b13d70bd41352d Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 04:34:13 +0800 Subject: [PATCH 02/73] Refactor/remove db from cycle manager (#20455) Signed-off-by: -LAN- --- .../console/app/workflow_app_log.py | 4 +- api/controllers/service_api/app/workflow.py | 5 +- .../app/apps/advanced_chat/app_generator.py | 4 +- .../advanced_chat/generate_task_pipeline.py | 31 +++--- .../common/workflow_response_converter.py | 17 ++-- api/core/app/apps/workflow/app_generator.py | 10 +- api/core/app/apps/workflow/app_runner.py | 2 +- .../apps/workflow/generate_task_pipeline.py | 41 ++++---- api/core/app/apps/workflow_app_runner.py | 2 +- api/core/app/entities/app_invoke_entities.py | 7 +- api/core/app/entities/queue_entities.py | 3 +- api/core/app/entities/task_entities.py | 6 +- api/core/ops/entities/trace_entity.py | 13 ++- .../ops/langsmith_trace/langsmith_trace.py | 2 +- api/core/ops/opik_trace/opik_trace.py | 2 +- api/core/ops/ops_trace_manager.py | 4 +- api/core/ops/weave_trace/weave_trace.py | 2 +- .../rag/extractor/entity/extract_setting.py | 8 +- api/core/rag/models/document.py | 5 +- ...qlalchemy_workflow_execution_repository.py | 30 ++++-- ...hemy_workflow_node_execution_repository.py | 11 +-- api/core/workflow/entities/node_entities.py | 28 +----- ...tion_entities.py => workflow_execution.py} | 16 ++- ...entities.py => workflow_node_execution.py} | 30 +++++- .../entities/runtime_route_state.py | 2 +- .../workflow/graph_engine/graph_engine.py | 5 +- api/core/workflow/nodes/agent/agent_node.py | 2 +- api/core/workflow/nodes/answer/answer_node.py | 2 +- api/core/workflow/nodes/base/node.py | 2 +- api/core/workflow/nodes/code/code_node.py | 2 +- .../workflow/nodes/document_extractor/node.py | 2 +- api/core/workflow/nodes/end/end_node.py | 2 +- api/core/workflow/nodes/event/event.py | 2 +- api/core/workflow/nodes/http_request/node.py | 2 +- .../workflow/nodes/if_else/if_else_node.py | 2 +- .../nodes/iteration/iteration_node.py | 3 +- .../nodes/iteration/iteration_start_node.py | 2 +- .../knowledge_retrieval_node.py | 2 +- api/core/workflow/nodes/list_operator/node.py | 2 +- api/core/workflow/nodes/llm/node.py | 4 +- api/core/workflow/nodes/loop/loop_end_node.py | 2 +- api/core/workflow/nodes/loop/loop_node.py | 4 +- .../workflow/nodes/loop/loop_start_node.py | 2 +- .../parameter_extractor_node.py | 4 +- .../question_classifier_node.py | 4 +- api/core/workflow/nodes/start/start_node.py | 2 +- .../template_transform_node.py | 2 +- api/core/workflow/nodes/tool/tool_node.py | 4 +- .../variable_aggregator_node.py | 2 +- .../nodes/variable_assigner/v1/node.py | 2 +- .../nodes/variable_assigner/v2/node.py | 2 +- .../{repository => repositories}/__init__.py | 2 +- .../workflow_execution_repository.py | 2 +- .../workflow_node_execution_repository.py | 2 +- api/core/workflow/workflow_cycle_manager.py | 81 +++++++--------- api/models/__init__.py | 8 +- api/models/model.py | 20 ++-- api/models/workflow.py | 24 ----- api/pytest.ini | 1 - api/services/workflow_app_service.py | 4 +- api/services/workflow_run_service.py | 2 +- api/services/workflow_service.py | 9 +- .../workflow/nodes/test_code.py | 3 +- .../workflow/nodes/test_llm.py | 3 +- .../nodes/test_parameter_extractor.py | 3 +- .../workflow/nodes/test_template_transform.py | 3 +- .../workflow/nodes/test_tool.py | 3 +- .../prompt/test_extract_thread_messages.py | 44 ++++----- .../rag/datasource/vdb/milvus/test_milvus.py | 2 +- .../graph_engine/test_graph_engine.py | 3 +- .../core/workflow/nodes/answer/test_answer.py | 3 +- .../http_request/test_http_request_node.py | 3 +- .../nodes/iteration/test_iteration.py | 3 +- .../core/workflow/nodes/test_answer.py | 3 +- .../workflow/nodes/test_continue_on_error.py | 3 +- .../nodes/test_document_extractor_node.py | 2 +- .../core/workflow/nodes/test_if_else.py | 3 +- .../core/workflow/nodes/test_list_operator.py | 2 +- .../workflow/nodes/tool/test_tool_node.py | 3 +- .../workflow/test_workflow_cycle_manager.py | 97 ++++++++++--------- .../test_sqlalchemy_repository.py | 15 +-- 81 files changed, 345 insertions(+), 362 deletions(-) rename api/core/workflow/entities/{workflow_execution_entities.py => workflow_execution.py} (89%) rename api/core/workflow/entities/{node_execution_entities.py => workflow_node_execution.py} (75%) rename api/core/workflow/{repository => repositories}/__init__.py (69%) rename api/core/workflow/{repository => repositories}/workflow_execution_repository.py (94%) rename api/core/workflow/{repository => repositories}/workflow_node_execution_repository.py (97%) diff --git a/api/controllers/console/app/workflow_app_log.py b/api/controllers/console/app/workflow_app_log.py index c475aea9fc..b9579e2120 100644 --- a/api/controllers/console/app/workflow_app_log.py +++ b/api/controllers/console/app/workflow_app_log.py @@ -6,12 +6,12 @@ from sqlalchemy.orm import Session from controllers.console import api from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required +from core.workflow.entities.workflow_execution import WorkflowExecutionStatus from extensions.ext_database import db from fields.workflow_app_log_fields import workflow_app_log_pagination_fields from libs.login import login_required from models import App from models.model import AppMode -from models.workflow import WorkflowRunStatus from services.workflow_app_service import WorkflowAppService @@ -38,7 +38,7 @@ class WorkflowAppLogApi(Resource): parser.add_argument("limit", type=int_range(1, 100), default=20, location="args") args = parser.parse_args() - args.status = WorkflowRunStatus(args.status) if args.status else None + args.status = WorkflowExecutionStatus(args.status) if args.status else None if args.created_at__before: args.created_at__before = isoparse(args.created_at__before) diff --git a/api/controllers/service_api/app/workflow.py b/api/controllers/service_api/app/workflow.py index e9bb2b046a..df52b49424 100644 --- a/api/controllers/service_api/app/workflow.py +++ b/api/controllers/service_api/app/workflow.py @@ -24,12 +24,13 @@ from core.errors.error import ( QuotaExceededError, ) from core.model_runtime.errors.invoke import InvokeError +from core.workflow.entities.workflow_execution import WorkflowExecutionStatus from extensions.ext_database import db from fields.workflow_app_log_fields import workflow_app_log_pagination_fields from libs import helper from libs.helper import TimestampField from models.model import App, AppMode, EndUser -from models.workflow import WorkflowRun, WorkflowRunStatus +from models.workflow import WorkflowRun from services.app_generate_service import AppGenerateService from services.errors.llm import InvokeRateLimitError from services.workflow_app_service import WorkflowAppService @@ -138,7 +139,7 @@ class WorkflowAppLogApi(Resource): parser.add_argument("limit", type=int_range(1, 100), default=20, location="args") args = parser.parse_args() - args.status = WorkflowRunStatus(args.status) if args.status else None + args.status = WorkflowExecutionStatus(args.status) if args.status else None if args.created_at__before: args.created_at__before = isoparse(args.created_at__before) diff --git a/api/core/app/apps/advanced_chat/app_generator.py b/api/core/app/apps/advanced_chat/app_generator.py index fdd1a776f8..8c85f91d7e 100644 --- a/api/core/app/apps/advanced_chat/app_generator.py +++ b/api/core/app/apps/advanced_chat/app_generator.py @@ -27,8 +27,8 @@ from core.ops.ops_trace_manager import TraceQueueManager from core.prompt.utils.get_thread_messages_length import get_thread_messages_length from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchemyWorkflowExecutionRepository -from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository +from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from extensions.ext_database import db from factories import file_factory from models import Account, App, Conversation, EndUser, Message, Workflow, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/app/apps/advanced_chat/generate_task_pipeline.py b/api/core/app/apps/advanced_chat/generate_task_pipeline.py index 0a2401f953..ffce11187b 100644 --- a/api/core/app/apps/advanced_chat/generate_task_pipeline.py +++ b/api/core/app/apps/advanced_chat/generate_task_pipeline.py @@ -62,21 +62,19 @@ from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk from core.model_runtime.entities.llm_entities import LLMUsage from core.model_runtime.utils.encoders import jsonable_encoder from core.ops.ops_trace_manager import TraceQueueManager +from core.workflow.entities.workflow_execution import WorkflowExecutionStatus, WorkflowType from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState from core.workflow.nodes import NodeType -from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.workflow_cycle_manager import WorkflowCycleManager +from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository +from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from core.workflow.workflow_cycle_manager import CycleManagerWorkflowInfo, WorkflowCycleManager from events.message_event import message_was_created from extensions.ext_database import db from models import Conversation, EndUser, Message, MessageFile from models.account import Account from models.enums import CreatorUserRole -from models.workflow import ( - Workflow, - WorkflowRunStatus, -) +from models.workflow import Workflow logger = logging.getLogger(__name__) @@ -128,6 +126,12 @@ class AdvancedChatAppGenerateTaskPipeline: SystemVariableKey.WORKFLOW_ID: workflow.id, SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_run_id, }, + workflow_info=CycleManagerWorkflowInfo( + workflow_id=workflow.id, + workflow_type=WorkflowType(workflow.type), + version=workflow.version, + graph_data=workflow.graph_dict, + ), workflow_execution_repository=workflow_execution_repository, workflow_node_execution_repository=workflow_node_execution_repository, ) @@ -302,15 +306,12 @@ class AdvancedChatAppGenerateTaskPipeline: with Session(db.engine, expire_on_commit=False) as session: # init workflow run - workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start( - session=session, - workflow_id=self._workflow_id, - ) - self._workflow_run_id = workflow_execution.id + workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start() + self._workflow_run_id = workflow_execution.id_ message = self._get_message(session=session) if not message: raise ValueError(f"Message not found: {self._message_id}") - message.workflow_run_id = workflow_execution.id + message.workflow_run_id = workflow_execution.id_ workflow_start_resp = self._workflow_response_converter.workflow_start_to_stream_response( task_id=self._application_generate_entity.task_id, workflow_execution=workflow_execution, @@ -550,7 +551,7 @@ class AdvancedChatAppGenerateTaskPipeline: workflow_run_id=self._workflow_run_id, total_tokens=graph_runtime_state.total_tokens, total_steps=graph_runtime_state.node_run_steps, - status=WorkflowRunStatus.FAILED, + status=WorkflowExecutionStatus.FAILED, error_message=event.error, conversation_id=self._conversation_id, trace_manager=trace_manager, @@ -576,7 +577,7 @@ class AdvancedChatAppGenerateTaskPipeline: workflow_run_id=self._workflow_run_id, total_tokens=graph_runtime_state.total_tokens, total_steps=graph_runtime_state.node_run_steps, - status=WorkflowRunStatus.STOPPED, + status=WorkflowExecutionStatus.STOPPED, error_message=event.get_stop_reason(), conversation_id=self._conversation_id, trace_manager=trace_manager, diff --git a/api/core/app/apps/common/workflow_response_converter.py b/api/core/app/apps/common/workflow_response_converter.py index 7669bf74bb..6df25b20e3 100644 --- a/api/core/app/apps/common/workflow_response_converter.py +++ b/api/core/app/apps/common/workflow_response_converter.py @@ -44,15 +44,14 @@ from core.app.entities.task_entities import ( ) from core.file import FILE_MODEL_IDENTITY, File from core.tools.tool_manager import ToolManager -from core.workflow.entities.node_execution_entities import NodeExecution -from core.workflow.entities.workflow_execution_entities import WorkflowExecution +from core.workflow.entities.workflow_execution import WorkflowExecution +from core.workflow.entities.workflow_node_execution import NodeExecution, WorkflowNodeExecutionStatus from core.workflow.nodes import NodeType from core.workflow.nodes.tool.entities import ToolNodeData from models import ( Account, CreatorUserRole, EndUser, - WorkflowNodeExecutionStatus, WorkflowRun, ) @@ -73,11 +72,10 @@ class WorkflowResponseConverter: ) -> WorkflowStartStreamResponse: return WorkflowStartStreamResponse( task_id=task_id, - workflow_run_id=workflow_execution.id, + workflow_run_id=workflow_execution.id_, data=WorkflowStartStreamResponse.Data( - id=workflow_execution.id, + id=workflow_execution.id_, workflow_id=workflow_execution.workflow_id, - sequence_number=workflow_execution.sequence_number, inputs=workflow_execution.inputs, created_at=int(workflow_execution.started_at.timestamp()), ), @@ -91,7 +89,7 @@ class WorkflowResponseConverter: workflow_execution: WorkflowExecution, ) -> WorkflowFinishStreamResponse: created_by = None - workflow_run = session.scalar(select(WorkflowRun).where(WorkflowRun.id == workflow_execution.id)) + workflow_run = session.scalar(select(WorkflowRun).where(WorkflowRun.id == workflow_execution.id_)) assert workflow_run is not None if workflow_run.created_by_role == CreatorUserRole.ACCOUNT: stmt = select(Account).where(Account.id == workflow_run.created_by) @@ -122,11 +120,10 @@ class WorkflowResponseConverter: return WorkflowFinishStreamResponse( task_id=task_id, - workflow_run_id=workflow_execution.id, + workflow_run_id=workflow_execution.id_, data=WorkflowFinishStreamResponse.Data( - id=workflow_execution.id, + id=workflow_execution.id_, workflow_id=workflow_execution.workflow_id, - sequence_number=workflow_execution.sequence_number, status=workflow_execution.status, outputs=workflow_execution.outputs, error=workflow_execution.error_message, diff --git a/api/core/app/apps/workflow/app_generator.py b/api/core/app/apps/workflow/app_generator.py index 6ea90e5a3d..f4aec3479b 100644 --- a/api/core/app/apps/workflow/app_generator.py +++ b/api/core/app/apps/workflow/app_generator.py @@ -25,8 +25,8 @@ from core.model_runtime.errors.invoke import InvokeAuthorizationError from core.ops.ops_trace_manager import TraceQueueManager from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.repositories.sqlalchemy_workflow_execution_repository import SQLAlchemyWorkflowExecutionRepository -from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository +from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from extensions.ext_database import db from factories import file_factory from models import Account, App, EndUser, Workflow, WorkflowNodeExecutionTriggeredFrom @@ -132,7 +132,7 @@ class WorkflowAppGenerator(BaseAppGenerator): invoke_from=invoke_from, call_depth=call_depth, trace_manager=trace_manager, - workflow_run_id=workflow_run_id, + workflow_execution_id=workflow_run_id, ) contexts.plugin_tool_providers.set({}) @@ -279,7 +279,7 @@ class WorkflowAppGenerator(BaseAppGenerator): single_iteration_run=WorkflowAppGenerateEntity.SingleIterationRunEntity( node_id=node_id, inputs=args["inputs"] ), - workflow_run_id=str(uuid.uuid4()), + workflow_execution_id=str(uuid.uuid4()), ) contexts.plugin_tool_providers.set({}) contexts.plugin_tool_providers_lock.set(threading.Lock()) @@ -355,7 +355,7 @@ class WorkflowAppGenerator(BaseAppGenerator): invoke_from=InvokeFrom.DEBUGGER, extras={"auto_generate_conversation_name": False}, single_loop_run=WorkflowAppGenerateEntity.SingleLoopRunEntity(node_id=node_id, inputs=args["inputs"]), - workflow_run_id=str(uuid.uuid4()), + workflow_execution_id=str(uuid.uuid4()), ) contexts.plugin_tool_providers.set({}) contexts.plugin_tool_providers_lock.set(threading.Lock()) diff --git a/api/core/app/apps/workflow/app_runner.py b/api/core/app/apps/workflow/app_runner.py index b38ee18ac4..c93a49b7e4 100644 --- a/api/core/app/apps/workflow/app_runner.py +++ b/api/core/app/apps/workflow/app_runner.py @@ -95,7 +95,7 @@ class WorkflowAppRunner(WorkflowBasedAppRunner): SystemVariableKey.USER_ID: user_id, SystemVariableKey.APP_ID: app_config.app_id, SystemVariableKey.WORKFLOW_ID: app_config.workflow_id, - SystemVariableKey.WORKFLOW_RUN_ID: self.application_generate_entity.workflow_run_id, + SystemVariableKey.WORKFLOW_RUN_ID: self.application_generate_entity.workflow_execution_id, } variable_pool = VariablePool( diff --git a/api/core/app/apps/workflow/generate_task_pipeline.py b/api/core/app/apps/workflow/generate_task_pipeline.py index 0291f49cac..e678774fae 100644 --- a/api/core/app/apps/workflow/generate_task_pipeline.py +++ b/api/core/app/apps/workflow/generate_task_pipeline.py @@ -55,11 +55,11 @@ from core.app.entities.task_entities import ( from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk from core.ops.ops_trace_manager import TraceQueueManager -from core.workflow.entities.workflow_execution_entities import WorkflowExecution +from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType from core.workflow.enums import SystemVariableKey -from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.workflow_cycle_manager import WorkflowCycleManager +from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository +from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from core.workflow.workflow_cycle_manager import CycleManagerWorkflowInfo, WorkflowCycleManager from extensions.ext_database import db from models.account import Account from models.enums import CreatorUserRole @@ -69,7 +69,6 @@ from models.workflow import ( WorkflowAppLog, WorkflowAppLogCreatedFrom, WorkflowRun, - WorkflowRunStatus, ) logger = logging.getLogger(__name__) @@ -114,8 +113,14 @@ class WorkflowAppGenerateTaskPipeline: SystemVariableKey.USER_ID: user_session_id, SystemVariableKey.APP_ID: application_generate_entity.app_config.app_id, SystemVariableKey.WORKFLOW_ID: workflow.id, - SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_run_id, + SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_execution_id, }, + workflow_info=CycleManagerWorkflowInfo( + workflow_id=workflow.id, + workflow_type=WorkflowType(workflow.type), + version=workflow.version, + graph_data=workflow.graph_dict, + ), workflow_execution_repository=workflow_execution_repository, workflow_node_execution_repository=workflow_node_execution_repository, ) @@ -266,17 +271,13 @@ class WorkflowAppGenerateTaskPipeline: # override graph runtime state graph_runtime_state = event.graph_runtime_state - with Session(db.engine, expire_on_commit=False) as session: - # init workflow run - workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start( - session=session, - workflow_id=self._workflow_id, - ) - self._workflow_run_id = workflow_execution.id - start_resp = self._workflow_response_converter.workflow_start_to_stream_response( - task_id=self._application_generate_entity.task_id, - workflow_execution=workflow_execution, - ) + # init workflow run + workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start() + self._workflow_run_id = workflow_execution.id_ + start_resp = self._workflow_response_converter.workflow_start_to_stream_response( + task_id=self._application_generate_entity.task_id, + workflow_execution=workflow_execution, + ) yield start_resp elif isinstance( @@ -511,9 +512,9 @@ class WorkflowAppGenerateTaskPipeline: workflow_run_id=self._workflow_run_id, total_tokens=graph_runtime_state.total_tokens, total_steps=graph_runtime_state.node_run_steps, - status=WorkflowRunStatus.FAILED + status=WorkflowExecutionStatus.FAILED if isinstance(event, QueueWorkflowFailedEvent) - else WorkflowRunStatus.STOPPED, + else WorkflowExecutionStatus.STOPPED, error_message=event.error if isinstance(event, QueueWorkflowFailedEvent) else event.get_stop_reason(), @@ -557,7 +558,7 @@ class WorkflowAppGenerateTaskPipeline: tts_publisher.publish(None) def _save_workflow_app_log(self, *, session: Session, workflow_execution: WorkflowExecution) -> None: - workflow_run = session.scalar(select(WorkflowRun).where(WorkflowRun.id == workflow_execution.id)) + workflow_run = session.scalar(select(WorkflowRun).where(WorkflowRun.id == workflow_execution.id_)) assert workflow_run is not None invoke_from = self._application_generate_entity.invoke_from if invoke_from == InvokeFrom.SERVICE_API: diff --git a/api/core/app/apps/workflow_app_runner.py b/api/core/app/apps/workflow_app_runner.py index 0884fac4a9..613bd8e8fc 100644 --- a/api/core/app/apps/workflow_app_runner.py +++ b/api/core/app/apps/workflow_app_runner.py @@ -29,8 +29,8 @@ from core.app.entities.queue_entities import ( QueueWorkflowStartedEvent, QueueWorkflowSucceededEvent, ) -from core.workflow.entities.node_entities import NodeRunMetadataKey from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey from core.workflow.graph_engine.entities.event import ( AgentLogEvent, GraphEngineEvent, diff --git a/api/core/app/entities/app_invoke_entities.py b/api/core/app/entities/app_invoke_entities.py index 56e6b46a60..c0d99693b0 100644 --- a/api/core/app/entities/app_invoke_entities.py +++ b/api/core/app/entities/app_invoke_entities.py @@ -76,6 +76,8 @@ class AppGenerateEntity(BaseModel): App Generate Entity. """ + model_config = ConfigDict(arbitrary_types_allowed=True) + task_id: str # app config @@ -99,9 +101,6 @@ class AppGenerateEntity(BaseModel): # tracing instance trace_manager: Optional[TraceQueueManager] = None - class Config: - arbitrary_types_allowed = True - class EasyUIBasedAppGenerateEntity(AppGenerateEntity): """ @@ -205,7 +204,7 @@ class WorkflowAppGenerateEntity(AppGenerateEntity): # app config app_config: WorkflowUIBasedAppConfig - workflow_run_id: str + workflow_execution_id: str class SingleIterationRunEntity(BaseModel): """ diff --git a/api/core/app/entities/queue_entities.py b/api/core/app/entities/queue_entities.py index 7228020e9b..e4ff123134 100644 --- a/api/core/app/entities/queue_entities.py +++ b/api/core/app/entities/queue_entities.py @@ -6,7 +6,8 @@ from typing import Any, Optional from pydantic import BaseModel from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk -from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunMetadataKey +from core.workflow.entities.node_entities import AgentNodeStrategyInit +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState from core.workflow.nodes import NodeType from core.workflow.nodes.base import BaseNodeData diff --git a/api/core/app/entities/task_entities.py b/api/core/app/entities/task_entities.py index 9b2bfcbf61..39b530cdfe 100644 --- a/api/core/app/entities/task_entities.py +++ b/api/core/app/entities/task_entities.py @@ -6,8 +6,8 @@ from pydantic import BaseModel, ConfigDict from core.model_runtime.entities.llm_entities import LLMResult from core.model_runtime.utils.encoders import jsonable_encoder -from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunMetadataKey -from models.workflow import WorkflowNodeExecutionStatus +from core.workflow.entities.node_entities import AgentNodeStrategyInit +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus class TaskState(BaseModel): @@ -189,7 +189,6 @@ class WorkflowStartStreamResponse(StreamResponse): id: str workflow_id: str - sequence_number: int inputs: Mapping[str, Any] created_at: int @@ -210,7 +209,6 @@ class WorkflowFinishStreamResponse(StreamResponse): id: str workflow_id: str - sequence_number: int status: str outputs: Optional[Mapping[str, Any]] = None error: Optional[str] = None diff --git a/api/core/ops/entities/trace_entity.py b/api/core/ops/entities/trace_entity.py index f0e34c0cd7..151fa2aaf4 100644 --- a/api/core/ops/entities/trace_entity.py +++ b/api/core/ops/entities/trace_entity.py @@ -3,7 +3,7 @@ from datetime import datetime from enum import StrEnum from typing import Any, Optional, Union -from pydantic import BaseModel, ConfigDict, field_validator +from pydantic import BaseModel, ConfigDict, field_serializer, field_validator class BaseTraceInfo(BaseModel): @@ -24,10 +24,13 @@ class BaseTraceInfo(BaseModel): return v return "" - class Config: - json_encoders = { - datetime: lambda v: v.isoformat(), - } + model_config = ConfigDict(protected_namespaces=()) + + @field_serializer("start_time", "end_time") + def serialize_datetime(self, dt: datetime | None) -> str | None: + if dt is None: + return None + return dt.isoformat() class WorkflowTraceInfo(BaseTraceInfo): diff --git a/api/core/ops/langsmith_trace/langsmith_trace.py b/api/core/ops/langsmith_trace/langsmith_trace.py index 6631727c79..43b866e1af 100644 --- a/api/core/ops/langsmith_trace/langsmith_trace.py +++ b/api/core/ops/langsmith_trace/langsmith_trace.py @@ -28,7 +28,7 @@ from core.ops.langsmith_trace.entities.langsmith_trace_entity import ( ) from core.ops.utils import filter_none_values, generate_dotted_order from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.node_entities import NodeRunMetadataKey +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/ops/opik_trace/opik_trace.py b/api/core/ops/opik_trace/opik_trace.py index 6c159a4831..7d68dca831 100644 --- a/api/core/ops/opik_trace/opik_trace.py +++ b/api/core/ops/opik_trace/opik_trace.py @@ -22,7 +22,7 @@ from core.ops.entities.trace_entity import ( WorkflowTraceInfo, ) from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.node_entities import NodeRunMetadataKey +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/ops/ops_trace_manager.py b/api/core/ops/ops_trace_manager.py index 32301e11e7..addf164e6f 100644 --- a/api/core/ops/ops_trace_manager.py +++ b/api/core/ops/ops_trace_manager.py @@ -30,7 +30,7 @@ from core.ops.entities.trace_entity import ( WorkflowTraceInfo, ) from core.ops.utils import get_message_data -from core.workflow.entities.workflow_execution_entities import WorkflowExecution +from core.workflow.entities.workflow_execution import WorkflowExecution from extensions.ext_database import db from extensions.ext_storage import storage from models.model import App, AppModelConfig, Conversation, Message, MessageFile, TraceAppConfig @@ -386,7 +386,7 @@ class TraceTask: ): self.trace_type = trace_type self.message_id = message_id - self.workflow_run_id = workflow_execution.id if workflow_execution else None + self.workflow_run_id = workflow_execution.id_ if workflow_execution else None self.conversation_id = conversation_id self.user_id = user_id self.timer = timer diff --git a/api/core/ops/weave_trace/weave_trace.py b/api/core/ops/weave_trace/weave_trace.py index a4f38dfbba..d1bd97176e 100644 --- a/api/core/ops/weave_trace/weave_trace.py +++ b/api/core/ops/weave_trace/weave_trace.py @@ -23,7 +23,7 @@ from core.ops.entities.trace_entity import ( ) from core.ops.weave_trace.entities.weave_trace_entity import WeaveTraceModel from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.node_entities import NodeRunMetadataKey +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom diff --git a/api/core/rag/extractor/entity/extract_setting.py b/api/core/rag/extractor/entity/extract_setting.py index 7c00c668dd..1593ad1475 100644 --- a/api/core/rag/extractor/entity/extract_setting.py +++ b/api/core/rag/extractor/entity/extract_setting.py @@ -27,6 +27,8 @@ class WebsiteInfo(BaseModel): website import info. """ + model_config = ConfigDict(arbitrary_types_allowed=True) + provider: str job_id: str url: str @@ -34,12 +36,6 @@ class WebsiteInfo(BaseModel): tenant_id: str only_main_content: bool = False - class Config: - arbitrary_types_allowed = True - - def __init__(self, **data) -> None: - super().__init__(**data) - class ExtractSetting(BaseModel): """ diff --git a/api/core/rag/models/document.py b/api/core/rag/models/document.py index 421cdc05df..04a3428ad8 100644 --- a/api/core/rag/models/document.py +++ b/api/core/rag/models/document.py @@ -45,13 +45,12 @@ class BaseDocumentTransformer(ABC): .. code-block:: python class EmbeddingsRedundantFilter(BaseDocumentTransformer, BaseModel): + model_config = ConfigDict(arbitrary_types_allowed=True) + embeddings: Embeddings similarity_fn: Callable = cosine_similarity similarity_threshold: float = 0.95 - class Config: - arbitrary_types_allowed = True - def transform_documents( self, documents: Sequence[Document], **kwargs: Any ) -> Sequence[Document]: diff --git a/api/core/repositories/sqlalchemy_workflow_execution_repository.py b/api/core/repositories/sqlalchemy_workflow_execution_repository.py index c1a71b45d0..19086cffff 100644 --- a/api/core/repositories/sqlalchemy_workflow_execution_repository.py +++ b/api/core/repositories/sqlalchemy_workflow_execution_repository.py @@ -10,12 +10,12 @@ from sqlalchemy import select from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker -from core.workflow.entities.workflow_execution_entities import ( +from core.workflow.entities.workflow_execution import ( WorkflowExecution, WorkflowExecutionStatus, WorkflowType, ) -from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository +from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository from models import ( Account, CreatorUserRole, @@ -104,10 +104,9 @@ class SQLAlchemyWorkflowExecutionRepository(WorkflowExecutionRepository): status = WorkflowExecutionStatus(db_model.status) return WorkflowExecution( - id=db_model.id, + id_=db_model.id, workflow_id=db_model.workflow_id, - sequence_number=db_model.sequence_number, - type=WorkflowType(db_model.type), + workflow_type=WorkflowType(db_model.type), workflow_version=db_model.version, graph=graph, inputs=inputs, @@ -140,14 +139,29 @@ class SQLAlchemyWorkflowExecutionRepository(WorkflowExecutionRepository): raise ValueError("created_by_role is required in repository constructor") db_model = WorkflowRun() - db_model.id = domain_model.id + db_model.id = domain_model.id_ db_model.tenant_id = self._tenant_id if self._app_id is not None: db_model.app_id = self._app_id db_model.workflow_id = domain_model.workflow_id db_model.triggered_from = self._triggered_from - db_model.sequence_number = domain_model.sequence_number - db_model.type = domain_model.type + + # Check if this is a new record + with self._session_factory() as session: + existing = session.scalar(select(WorkflowRun).where(WorkflowRun.id == domain_model.id_)) + if not existing: + # For new records, get the next sequence number + stmt = select(WorkflowRun.sequence_number).where( + WorkflowRun.app_id == self._app_id, + WorkflowRun.tenant_id == self._tenant_id, + ) + max_sequence = session.scalar(stmt.order_by(WorkflowRun.sequence_number.desc())) + db_model.sequence_number = (max_sequence or 0) + 1 + else: + # For updates, keep the existing sequence number + db_model.sequence_number = existing.sequence_number + + db_model.type = domain_model.workflow_type db_model.version = domain_model.workflow_version db_model.graph = json.dumps(domain_model.graph) if domain_model.graph else None db_model.inputs = json.dumps(domain_model.inputs) if domain_model.inputs else None diff --git a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py index 8d916a19db..ee4465db5d 100644 --- a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py +++ b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py @@ -12,19 +12,18 @@ from sqlalchemy.engine import Engine from sqlalchemy.orm import sessionmaker from core.model_runtime.utils.encoders import jsonable_encoder -from core.workflow.entities.node_entities import NodeRunMetadataKey -from core.workflow.entities.node_execution_entities import ( +from core.workflow.entities.workflow_node_execution import ( NodeExecution, - NodeExecutionStatus, + NodeRunMetadataKey, + WorkflowNodeExecutionStatus, ) from core.workflow.nodes.enums import NodeType -from core.workflow.repository.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository +from core.workflow.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository from models import ( Account, CreatorUserRole, EndUser, WorkflowNodeExecution, - WorkflowNodeExecutionStatus, WorkflowNodeExecutionTriggeredFrom, ) @@ -106,7 +105,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) metadata = {NodeRunMetadataKey(k): v for k, v in db_model.execution_metadata_dict.items()} # Convert status to domain enum - status = NodeExecutionStatus(db_model.status) + status = WorkflowNodeExecutionStatus(db_model.status) return NodeExecution( id=db_model.id, diff --git a/api/core/workflow/entities/node_entities.py b/api/core/workflow/entities/node_entities.py index 82fd6cdc30..6d01028ffc 100644 --- a/api/core/workflow/entities/node_entities.py +++ b/api/core/workflow/entities/node_entities.py @@ -1,36 +1,10 @@ from collections.abc import Mapping -from enum import StrEnum from typing import Any, Optional from pydantic import BaseModel from core.model_runtime.entities.llm_entities import LLMUsage -from models.workflow import WorkflowNodeExecutionStatus - - -class NodeRunMetadataKey(StrEnum): - """ - Node Run Metadata Key. - """ - - TOTAL_TOKENS = "total_tokens" - TOTAL_PRICE = "total_price" - CURRENCY = "currency" - TOOL_INFO = "tool_info" - AGENT_LOG = "agent_log" - ITERATION_ID = "iteration_id" - ITERATION_INDEX = "iteration_index" - LOOP_ID = "loop_id" - LOOP_INDEX = "loop_index" - PARALLEL_ID = "parallel_id" - PARALLEL_START_NODE_ID = "parallel_start_node_id" - PARENT_PARALLEL_ID = "parent_parallel_id" - PARENT_PARALLEL_START_NODE_ID = "parent_parallel_start_node_id" - PARALLEL_MODE_RUN_ID = "parallel_mode_run_id" - ITERATION_DURATION_MAP = "iteration_duration_map" # single iteration duration if iteration node runs - LOOP_DURATION_MAP = "loop_duration_map" # single loop duration if loop node runs - ERROR_STRATEGY = "error_strategy" # node in continue on error mode return the field - LOOP_VARIABLE_MAP = "loop_variable_map" # single loop variable output +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus class NodeRunResult(BaseModel): diff --git a/api/core/workflow/entities/workflow_execution_entities.py b/api/core/workflow/entities/workflow_execution.py similarity index 89% rename from api/core/workflow/entities/workflow_execution_entities.py rename to api/core/workflow/entities/workflow_execution.py index 200d4697b5..781be4b3c6 100644 --- a/api/core/workflow/entities/workflow_execution_entities.py +++ b/api/core/workflow/entities/workflow_execution.py @@ -36,12 +36,10 @@ class WorkflowExecution(BaseModel): user, tenant, and app attributes. """ - id: str = Field(...) + id_: str = Field(...) workflow_id: str = Field(...) workflow_version: str = Field(...) - sequence_number: int = Field(...) - - type: WorkflowType = Field(...) + workflow_type: WorkflowType = Field(...) graph: Mapping[str, Any] = Field(...) inputs: Mapping[str, Any] = Field(...) @@ -69,20 +67,18 @@ class WorkflowExecution(BaseModel): def new( cls, *, - id: str, + id_: str, workflow_id: str, - sequence_number: int, - type: WorkflowType, + workflow_type: WorkflowType, workflow_version: str, graph: Mapping[str, Any], inputs: Mapping[str, Any], started_at: datetime, ) -> "WorkflowExecution": return WorkflowExecution( - id=id, + id_=id_, workflow_id=workflow_id, - sequence_number=sequence_number, - type=type, + workflow_type=workflow_type, workflow_version=workflow_version, graph=graph, inputs=inputs, diff --git a/api/core/workflow/entities/node_execution_entities.py b/api/core/workflow/entities/workflow_node_execution.py similarity index 75% rename from api/core/workflow/entities/node_execution_entities.py rename to api/core/workflow/entities/workflow_node_execution.py index 5e5ead062f..dccb6b1539 100644 --- a/api/core/workflow/entities/node_execution_entities.py +++ b/api/core/workflow/entities/workflow_node_execution.py @@ -13,11 +13,35 @@ from typing import Any, Optional from pydantic import BaseModel, Field -from core.workflow.entities.node_entities import NodeRunMetadataKey from core.workflow.nodes.enums import NodeType -class NodeExecutionStatus(StrEnum): +class NodeRunMetadataKey(StrEnum): + """ + Node Run Metadata Key. + """ + + TOTAL_TOKENS = "total_tokens" + TOTAL_PRICE = "total_price" + CURRENCY = "currency" + TOOL_INFO = "tool_info" + AGENT_LOG = "agent_log" + ITERATION_ID = "iteration_id" + ITERATION_INDEX = "iteration_index" + LOOP_ID = "loop_id" + LOOP_INDEX = "loop_index" + PARALLEL_ID = "parallel_id" + PARALLEL_START_NODE_ID = "parallel_start_node_id" + PARENT_PARALLEL_ID = "parent_parallel_id" + PARENT_PARALLEL_START_NODE_ID = "parent_parallel_start_node_id" + PARALLEL_MODE_RUN_ID = "parallel_mode_run_id" + ITERATION_DURATION_MAP = "iteration_duration_map" # single iteration duration if iteration node runs + LOOP_DURATION_MAP = "loop_duration_map" # single loop duration if loop node runs + ERROR_STRATEGY = "error_strategy" # node in continue on error mode return the field + LOOP_VARIABLE_MAP = "loop_variable_map" # single loop variable output + + +class WorkflowNodeExecutionStatus(StrEnum): """ Node Execution Status Enum. """ @@ -61,7 +85,7 @@ class NodeExecution(BaseModel): outputs: Optional[Mapping[str, Any]] = None # Output variables produced by this node # Execution state - status: NodeExecutionStatus = NodeExecutionStatus.RUNNING # Current execution status + status: WorkflowNodeExecutionStatus = WorkflowNodeExecutionStatus.RUNNING # Current execution status error: Optional[str] = None # Error message if execution failed elapsed_time: float = Field(default=0.0) # Time taken for execution in seconds diff --git a/api/core/workflow/graph_engine/entities/runtime_route_state.py b/api/core/workflow/graph_engine/entities/runtime_route_state.py index 7683dcc9dc..f2d9c98936 100644 --- a/api/core/workflow/graph_engine/entities/runtime_route_state.py +++ b/api/core/workflow/graph_engine/entities/runtime_route_state.py @@ -6,7 +6,7 @@ from typing import Optional from pydantic import BaseModel, Field from core.workflow.entities.node_entities import NodeRunResult -from models.workflow import WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus class RouteNodeState(BaseModel): diff --git a/api/core/workflow/graph_engine/graph_engine.py b/api/core/workflow/graph_engine/graph_engine.py index f61965e07e..0d71a70971 100644 --- a/api/core/workflow/graph_engine/graph_engine.py +++ b/api/core/workflow/graph_engine/graph_engine.py @@ -14,8 +14,9 @@ from flask import Flask, current_app, has_request_context from configs import dify_config from core.app.apps.base_app_queue_manager import GenerateTaskStoppedError from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunResult from core.workflow.entities.variable_pool import VariablePool, VariableValue +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus from core.workflow.graph_engine.condition_handlers.condition_manager import ConditionManager from core.workflow.graph_engine.entities.event import ( BaseAgentEvent, @@ -54,7 +55,7 @@ from core.workflow.nodes.event import RunCompletedEvent, RunRetrieverResourceEve from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING from extensions.ext_database import db from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType logger = logging.getLogger(__name__) diff --git a/api/core/workflow/nodes/agent/agent_node.py b/api/core/workflow/nodes/agent/agent_node.py index 9bed8862fc..30b17cbd84 100644 --- a/api/core/workflow/nodes/agent/agent_node.py +++ b/api/core/workflow/nodes/agent/agent_node.py @@ -15,6 +15,7 @@ from core.tools.tool_manager import ToolManager from core.variables.segments import StringSegment from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.nodes.agent.entities import AgentNodeData, AgentOldVersionModelFeatures, ParamsAutoGenerated from core.workflow.nodes.base.entities import BaseNodeData @@ -25,7 +26,6 @@ from core.workflow.utils.variable_template_parser import VariableTemplateParser from extensions.ext_database import db from factories.agent_factory import get_plugin_agent_strategy from models.model import Conversation -from models.workflow import WorkflowNodeExecutionStatus class AgentNode(ToolNode): diff --git a/api/core/workflow/nodes/answer/answer_node.py b/api/core/workflow/nodes/answer/answer_node.py index 520cbdbb60..aa030870e2 100644 --- a/api/core/workflow/nodes/answer/answer_node.py +++ b/api/core/workflow/nodes/answer/answer_node.py @@ -3,6 +3,7 @@ from typing import Any, cast from core.variables import ArrayFileSegment, FileSegment from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.answer.answer_stream_generate_router import AnswerStreamGeneratorRouter from core.workflow.nodes.answer.entities import ( AnswerNodeData, @@ -13,7 +14,6 @@ from core.workflow.nodes.answer.entities import ( from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.utils.variable_template_parser import VariableTemplateParser -from models.workflow import WorkflowNodeExecutionStatus class AnswerNode(BaseNode[AnswerNodeData]): diff --git a/api/core/workflow/nodes/base/node.py b/api/core/workflow/nodes/base/node.py index e566770870..7da0c19740 100644 --- a/api/core/workflow/nodes/base/node.py +++ b/api/core/workflow/nodes/base/node.py @@ -4,9 +4,9 @@ from collections.abc import Generator, Mapping, Sequence from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar, Union, cast from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.enums import CONTINUE_ON_ERROR_NODE_TYPE, RETRY_ON_ERROR_NODE_TYPE, NodeType from core.workflow.nodes.event import NodeEvent, RunCompletedEvent -from models.workflow import WorkflowNodeExecutionStatus from .entities import BaseNodeData diff --git a/api/core/workflow/nodes/code/code_node.py b/api/core/workflow/nodes/code/code_node.py index 59dae792e8..61c08a7d71 100644 --- a/api/core/workflow/nodes/code/code_node.py +++ b/api/core/workflow/nodes/code/code_node.py @@ -8,10 +8,10 @@ from core.helper.code_executor.javascript.javascript_code_provider import Javasc from core.helper.code_executor.python3.python3_code_provider import Python3CodeProvider from core.variables.segments import ArrayFileSegment from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.code.entities import CodeNodeData from core.workflow.nodes.enums import NodeType -from models.workflow import WorkflowNodeExecutionStatus from .exc import ( CodeNodeError, diff --git a/api/core/workflow/nodes/document_extractor/node.py b/api/core/workflow/nodes/document_extractor/node.py index 65b5623a2e..d39eb9c932 100644 --- a/api/core/workflow/nodes/document_extractor/node.py +++ b/api/core/workflow/nodes/document_extractor/node.py @@ -26,9 +26,9 @@ from core.helper import ssrf_proxy from core.variables import ArrayFileSegment from core.variables.segments import FileSegment from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType -from models.workflow import WorkflowNodeExecutionStatus from .entities import DocumentExtractorNodeData from .exc import DocumentExtractorError, FileDownloadError, TextExtractionError, UnsupportedFileTypeError diff --git a/api/core/workflow/nodes/end/end_node.py b/api/core/workflow/nodes/end/end_node.py index 6acc915ab5..0e9756b243 100644 --- a/api/core/workflow/nodes/end/end_node.py +++ b/api/core/workflow/nodes/end/end_node.py @@ -1,8 +1,8 @@ from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.end.entities import EndNodeData from core.workflow.nodes.enums import NodeType -from models.workflow import WorkflowNodeExecutionStatus class EndNode(BaseNode[EndNodeData]): diff --git a/api/core/workflow/nodes/event/event.py b/api/core/workflow/nodes/event/event.py index 9fea3fbda3..f45919caf5 100644 --- a/api/core/workflow/nodes/event/event.py +++ b/api/core/workflow/nodes/event/event.py @@ -4,7 +4,7 @@ from pydantic import BaseModel, Field from core.model_runtime.entities.llm_entities import LLMUsage from core.workflow.entities.node_entities import NodeRunResult -from models.workflow import WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus class RunCompletedEvent(BaseModel): diff --git a/api/core/workflow/nodes/http_request/node.py b/api/core/workflow/nodes/http_request/node.py index 1c82637974..6b1ac57c06 100644 --- a/api/core/workflow/nodes/http_request/node.py +++ b/api/core/workflow/nodes/http_request/node.py @@ -8,12 +8,12 @@ from core.file import File, FileTransferMethod from core.tools.tool_file_manager import ToolFileManager from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_entities import VariableSelector +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.http_request.executor import Executor from core.workflow.utils import variable_template_parser from factories import file_factory -from models.workflow import WorkflowNodeExecutionStatus from .entities import ( HttpRequestNodeData, diff --git a/api/core/workflow/nodes/if_else/if_else_node.py b/api/core/workflow/nodes/if_else/if_else_node.py index cb51b1ddd5..976922f75d 100644 --- a/api/core/workflow/nodes/if_else/if_else_node.py +++ b/api/core/workflow/nodes/if_else/if_else_node.py @@ -4,12 +4,12 @@ from typing_extensions import deprecated from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.if_else.entities import IfElseNodeData from core.workflow.utils.condition.entities import Condition from core.workflow.utils.condition.processor import ConditionProcessor -from models.workflow import WorkflowNodeExecutionStatus class IfElseNode(BaseNode[IfElseNodeData]): diff --git a/api/core/workflow/nodes/iteration/iteration_node.py b/api/core/workflow/nodes/iteration/iteration_node.py index ea0b6863c9..7d22a78895 100644 --- a/api/core/workflow/nodes/iteration/iteration_node.py +++ b/api/core/workflow/nodes/iteration/iteration_node.py @@ -12,10 +12,10 @@ from flask import Flask, current_app, has_request_context from configs import dify_config from core.variables import ArrayVariable, IntegerVariable, NoneVariable from core.workflow.entities.node_entities import ( - NodeRunMetadataKey, NodeRunResult, ) from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus from core.workflow.graph_engine.entities.event import ( BaseGraphEvent, BaseNodeEvent, @@ -37,7 +37,6 @@ from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.event import NodeEvent, RunCompletedEvent from core.workflow.nodes.iteration.entities import ErrorHandleMode, IterationNodeData -from models.workflow import WorkflowNodeExecutionStatus from .exc import ( InvalidIteratorValueError, diff --git a/api/core/workflow/nodes/iteration/iteration_start_node.py b/api/core/workflow/nodes/iteration/iteration_start_node.py index fe955e47d1..bee481ebdb 100644 --- a/api/core/workflow/nodes/iteration/iteration_start_node.py +++ b/api/core/workflow/nodes/iteration/iteration_start_node.py @@ -1,8 +1,8 @@ from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.iteration.entities import IterationStartNodeData -from models.workflow import WorkflowNodeExecutionStatus class IterationStartNode(BaseNode[IterationStartNodeData]): diff --git a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py b/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py index 5955022e5f..2ddb4f8a0b 100644 --- a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py +++ b/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py @@ -24,6 +24,7 @@ from core.rag.retrieval.dataset_retrieval import DatasetRetrieval from core.rag.retrieval.retrieval_methods import RetrievalMethod from core.variables import StringSegment from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.enums import NodeType from core.workflow.nodes.event.event import ModelInvokeCompletedEvent from core.workflow.nodes.knowledge_retrieval.template_prompts import ( @@ -41,7 +42,6 @@ from extensions.ext_database import db from extensions.ext_redis import redis_client from libs.json_in_md_parser import parse_and_check_json_markdown from models.dataset import Dataset, DatasetMetadata, Document, RateLimitLog -from models.workflow import WorkflowNodeExecutionStatus from services.feature_service import FeatureService from .entities import KnowledgeRetrievalNodeData, ModelConfig diff --git a/api/core/workflow/nodes/list_operator/node.py b/api/core/workflow/nodes/list_operator/node.py index 04ccfc5405..e698d3f5d8 100644 --- a/api/core/workflow/nodes/list_operator/node.py +++ b/api/core/workflow/nodes/list_operator/node.py @@ -4,9 +4,9 @@ from typing import Any, Literal, Union from core.file import File from core.variables import ArrayFileSegment, ArrayNumberSegment, ArrayStringSegment from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType -from models.workflow import WorkflowNodeExecutionStatus from .entities import ListOperatorNodeData from .exc import InvalidConditionError, InvalidFilterValueError, InvalidKeyError, ListOperatorError diff --git a/api/core/workflow/nodes/llm/node.py b/api/core/workflow/nodes/llm/node.py index eeb44601ec..ceda0287fd 100644 --- a/api/core/workflow/nodes/llm/node.py +++ b/api/core/workflow/nodes/llm/node.py @@ -53,9 +53,10 @@ from core.variables import ( StringSegment, ) from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID -from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_entities import VariableSelector from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.event import InNodeEvent from core.workflow.nodes.base import BaseNode @@ -77,7 +78,6 @@ from core.workflow.utils.variable_template_parser import VariableTemplateParser from extensions.ext_database import db from models.model import Conversation from models.provider import Provider, ProviderType -from models.workflow import WorkflowNodeExecutionStatus from .entities import ( LLMNodeChatModelMessage, diff --git a/api/core/workflow/nodes/loop/loop_end_node.py b/api/core/workflow/nodes/loop/loop_end_node.py index 5d4ce0ccbe..327b9e234b 100644 --- a/api/core/workflow/nodes/loop/loop_end_node.py +++ b/api/core/workflow/nodes/loop/loop_end_node.py @@ -1,8 +1,8 @@ from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.loop.entities import LoopEndNodeData -from models.workflow import WorkflowNodeExecutionStatus class LoopEndNode(BaseNode[LoopEndNodeData]): diff --git a/api/core/workflow/nodes/loop/loop_node.py b/api/core/workflow/nodes/loop/loop_node.py index bad3e2b928..eef63c5a92 100644 --- a/api/core/workflow/nodes/loop/loop_node.py +++ b/api/core/workflow/nodes/loop/loop_node.py @@ -15,7 +15,8 @@ from core.variables import ( SegmentType, StringSegment, ) -from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus from core.workflow.graph_engine.entities.event import ( BaseGraphEvent, BaseNodeEvent, @@ -37,7 +38,6 @@ from core.workflow.nodes.enums import NodeType from core.workflow.nodes.event import NodeEvent, RunCompletedEvent from core.workflow.nodes.loop.entities import LoopNodeData from core.workflow.utils.condition.processor import ConditionProcessor -from models.workflow import WorkflowNodeExecutionStatus if TYPE_CHECKING: from core.workflow.entities.variable_pool import VariablePool diff --git a/api/core/workflow/nodes/loop/loop_start_node.py b/api/core/workflow/nodes/loop/loop_start_node.py index 7cf145e4e5..5a15f36044 100644 --- a/api/core/workflow/nodes/loop/loop_start_node.py +++ b/api/core/workflow/nodes/loop/loop_start_node.py @@ -1,8 +1,8 @@ from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.loop.entities import LoopStartNodeData -from models.workflow import WorkflowNodeExecutionStatus class LoopStartNode(BaseNode[LoopStartNodeData]): diff --git a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py index 8db1e432fc..244b15594e 100644 --- a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py +++ b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py @@ -25,13 +25,13 @@ from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.entities.advanced_prompt_entities import ChatModelMessage, CompletionModelPromptTemplate from core.prompt.simple_prompt_transform import ModelMode from core.prompt.utils.prompt_message_util import PromptMessageUtil -from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus from core.workflow.nodes.enums import NodeType from core.workflow.nodes.llm import LLMNode, ModelConfig from core.workflow.utils import variable_template_parser from extensions.ext_database import db -from models.workflow import WorkflowNodeExecutionStatus from .entities import ParameterExtractorNodeData from .exc import ( diff --git a/api/core/workflow/nodes/question_classifier/question_classifier_node.py b/api/core/workflow/nodes/question_classifier/question_classifier_node.py index b4f34a3bef..47626e983d 100644 --- a/api/core/workflow/nodes/question_classifier/question_classifier_node.py +++ b/api/core/workflow/nodes/question_classifier/question_classifier_node.py @@ -10,7 +10,8 @@ from core.model_runtime.utils.encoders import jsonable_encoder from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.simple_prompt_transform import ModelMode from core.prompt.utils.prompt_message_util import PromptMessageUtil -from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus from core.workflow.nodes.enums import NodeType from core.workflow.nodes.event import ModelInvokeCompletedEvent from core.workflow.nodes.llm import ( @@ -20,7 +21,6 @@ from core.workflow.nodes.llm import ( ) from core.workflow.utils.variable_template_parser import VariableTemplateParser from libs.json_in_md_parser import parse_and_check_json_markdown -from models.workflow import WorkflowNodeExecutionStatus from .entities import QuestionClassifierNodeData from .exc import InvalidModelTypeError diff --git a/api/core/workflow/nodes/start/start_node.py b/api/core/workflow/nodes/start/start_node.py index 1b47b81517..8839aec9d6 100644 --- a/api/core/workflow/nodes/start/start_node.py +++ b/api/core/workflow/nodes/start/start_node.py @@ -1,9 +1,9 @@ from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.start.entities import StartNodeData -from models.workflow import WorkflowNodeExecutionStatus class StartNode(BaseNode[StartNodeData]): diff --git a/api/core/workflow/nodes/template_transform/template_transform_node.py b/api/core/workflow/nodes/template_transform/template_transform_node.py index 22a1b21888..476cf7eee4 100644 --- a/api/core/workflow/nodes/template_transform/template_transform_node.py +++ b/api/core/workflow/nodes/template_transform/template_transform_node.py @@ -4,10 +4,10 @@ from typing import Any, Optional from core.helper.code_executor.code_executor import CodeExecutionError, CodeExecutor, CodeLanguage from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.template_transform.entities import TemplateTransformNodeData -from models.workflow import WorkflowNodeExecutionStatus MAX_TEMPLATE_TRANSFORM_OUTPUT_LENGTH = int(os.environ.get("TEMPLATE_TRANSFORM_MAX_LENGTH", "80000")) diff --git a/api/core/workflow/nodes/tool/tool_node.py b/api/core/workflow/nodes/tool/tool_node.py index c72ae5b69b..077e21ade4 100644 --- a/api/core/workflow/nodes/tool/tool_node.py +++ b/api/core/workflow/nodes/tool/tool_node.py @@ -14,8 +14,9 @@ from core.tools.tool_engine import ToolEngine from core.tools.utils.message_transformer import ToolFileMessageTransformer from core.variables.segments import ArrayAnySegment from core.variables.variables import ArrayAnyVariable -from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.event import AgentLogEvent from core.workflow.nodes.base import BaseNode @@ -25,7 +26,6 @@ from core.workflow.utils.variable_template_parser import VariableTemplateParser from extensions.ext_database import db from factories import file_factory from models import ToolFile -from models.workflow import WorkflowNodeExecutionStatus from services.tools.builtin_tools_manage_service import BuiltinToolManageService from .entities import ToolNodeData diff --git a/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py b/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py index 372496a8fa..db3e25b015 100644 --- a/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py +++ b/api/core/workflow/nodes/variable_aggregator/variable_aggregator_node.py @@ -1,8 +1,8 @@ from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.variable_aggregator.entities import VariableAssignerNodeData -from models.workflow import WorkflowNodeExecutionStatus class VariableAggregatorNode(BaseNode[VariableAssignerNodeData]): diff --git a/api/core/workflow/nodes/variable_assigner/v1/node.py b/api/core/workflow/nodes/variable_assigner/v1/node.py index 7c7f14c0b8..835e1d77b5 100644 --- a/api/core/workflow/nodes/variable_assigner/v1/node.py +++ b/api/core/workflow/nodes/variable_assigner/v1/node.py @@ -1,11 +1,11 @@ from core.variables import SegmentType, Variable from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.variable_assigner.common import helpers as common_helpers from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError from factories import variable_factory -from models.workflow import WorkflowNodeExecutionStatus from .node_data import VariableAssignerData, WriteMode diff --git a/api/core/workflow/nodes/variable_assigner/v2/node.py b/api/core/workflow/nodes/variable_assigner/v2/node.py index 6a7ad86b51..8759a55b34 100644 --- a/api/core/workflow/nodes/variable_assigner/v2/node.py +++ b/api/core/workflow/nodes/variable_assigner/v2/node.py @@ -6,11 +6,11 @@ from core.app.entities.app_invoke_entities import InvokeFrom from core.variables import SegmentType, Variable from core.workflow.constants import CONVERSATION_VARIABLE_NODE_ID from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.base import BaseNode from core.workflow.nodes.enums import NodeType from core.workflow.nodes.variable_assigner.common import helpers as common_helpers from core.workflow.nodes.variable_assigner.common.exc import VariableOperatorNodeError -from models.workflow import WorkflowNodeExecutionStatus from . import helpers from .constants import EMPTY_VALUE_MAPPING diff --git a/api/core/workflow/repository/__init__.py b/api/core/workflow/repositories/__init__.py similarity index 69% rename from api/core/workflow/repository/__init__.py rename to api/core/workflow/repositories/__init__.py index 672abb6583..a778151baa 100644 --- a/api/core/workflow/repository/__init__.py +++ b/api/core/workflow/repositories/__init__.py @@ -6,7 +6,7 @@ for accessing and manipulating data, regardless of the underlying storage mechanism. """ -from core.workflow.repository.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository +from core.workflow.repositories.workflow_node_execution_repository import OrderConfig, WorkflowNodeExecutionRepository __all__ = [ "OrderConfig", diff --git a/api/core/workflow/repository/workflow_execution_repository.py b/api/core/workflow/repositories/workflow_execution_repository.py similarity index 94% rename from api/core/workflow/repository/workflow_execution_repository.py rename to api/core/workflow/repositories/workflow_execution_repository.py index a39a98ee33..5917310c8b 100644 --- a/api/core/workflow/repository/workflow_execution_repository.py +++ b/api/core/workflow/repositories/workflow_execution_repository.py @@ -1,6 +1,6 @@ from typing import Optional, Protocol -from core.workflow.entities.workflow_execution_entities import WorkflowExecution +from core.workflow.entities.workflow_execution import WorkflowExecution class WorkflowExecutionRepository(Protocol): diff --git a/api/core/workflow/repository/workflow_node_execution_repository.py b/api/core/workflow/repositories/workflow_node_execution_repository.py similarity index 97% rename from api/core/workflow/repository/workflow_node_execution_repository.py rename to api/core/workflow/repositories/workflow_node_execution_repository.py index 3ca9e2ecab..8c83b5ea6c 100644 --- a/api/core/workflow/repository/workflow_node_execution_repository.py +++ b/api/core/workflow/repositories/workflow_node_execution_repository.py @@ -2,7 +2,7 @@ from collections.abc import Sequence from dataclasses import dataclass from typing import Literal, Optional, Protocol -from core.workflow.entities.node_execution_entities import NodeExecution +from core.workflow.entities.workflow_node_execution import NodeExecution @dataclass diff --git a/api/core/workflow/workflow_cycle_manager.py b/api/core/workflow/workflow_cycle_manager.py index 24e23af093..6e3c2f3f78 100644 --- a/api/core/workflow/workflow_cycle_manager.py +++ b/api/core/workflow/workflow_cycle_manager.py @@ -1,11 +1,9 @@ from collections.abc import Mapping +from dataclasses import dataclass from datetime import UTC, datetime from typing import Any, Optional, Union from uuid import uuid4 -from sqlalchemy import func, select -from sqlalchemy.orm import Session - from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, WorkflowAppGenerateEntity from core.app.entities.queue_entities import ( QueueNodeExceptionEvent, @@ -19,21 +17,24 @@ from core.app.entities.queue_entities import ( from core.app.task_pipeline.exc import WorkflowRunNotFoundError from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask -from core.workflow.entities.node_entities import NodeRunMetadataKey -from core.workflow.entities.node_execution_entities import ( +from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType +from core.workflow.entities.workflow_node_execution import ( NodeExecution, - NodeExecutionStatus, + NodeRunMetadataKey, + WorkflowNodeExecutionStatus, ) -from core.workflow.entities.workflow_execution_entities import WorkflowExecution, WorkflowExecutionStatus, WorkflowType from core.workflow.enums import SystemVariableKey -from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository +from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from core.workflow.workflow_entry import WorkflowEntry -from models import ( - Workflow, - WorkflowRun, - WorkflowRunStatus, -) + + +@dataclass +class CycleManagerWorkflowInfo: + workflow_id: str + workflow_type: WorkflowType + version: str + graph_data: Mapping[str, Any] class WorkflowCycleManager: @@ -42,32 +43,17 @@ class WorkflowCycleManager: *, application_generate_entity: Union[AdvancedChatAppGenerateEntity, WorkflowAppGenerateEntity], workflow_system_variables: dict[SystemVariableKey, Any], + workflow_info: CycleManagerWorkflowInfo, workflow_execution_repository: WorkflowExecutionRepository, workflow_node_execution_repository: WorkflowNodeExecutionRepository, ) -> None: self._application_generate_entity = application_generate_entity self._workflow_system_variables = workflow_system_variables + self._workflow_info = workflow_info self._workflow_execution_repository = workflow_execution_repository self._workflow_node_execution_repository = workflow_node_execution_repository - def handle_workflow_run_start( - self, - *, - session: Session, - workflow_id: str, - ) -> WorkflowExecution: - workflow_stmt = select(Workflow).where(Workflow.id == workflow_id) - workflow = session.scalar(workflow_stmt) - if not workflow: - raise ValueError(f"Workflow not found: {workflow_id}") - - max_sequence_stmt = select(func.max(WorkflowRun.sequence_number)).where( - WorkflowRun.tenant_id == workflow.tenant_id, - WorkflowRun.app_id == workflow.app_id, - ) - max_sequence = session.scalar(max_sequence_stmt) or 0 - new_sequence_number = max_sequence + 1 - + def handle_workflow_run_start(self) -> WorkflowExecution: inputs = {**self._application_generate_entity.inputs} for key, value in (self._workflow_system_variables or {}).items(): if key.value == "conversation": @@ -81,12 +67,11 @@ class WorkflowCycleManager: # TODO: This workflow_run_id should always not be None, maybe we can use a more elegant way to handle this execution_id = str(self._workflow_system_variables.get(SystemVariableKey.WORKFLOW_RUN_ID) or uuid4()) execution = WorkflowExecution.new( - id=execution_id, - workflow_id=workflow.id, - sequence_number=new_sequence_number, - type=WorkflowType(workflow.type), - workflow_version=workflow.version, - graph=workflow.graph_dict, + id_=execution_id, + workflow_id=self._workflow_info.workflow_id, + workflow_type=self._workflow_info.workflow_type, + workflow_version=self._workflow_info.version, + graph=self._workflow_info.graph_data, inputs=inputs, started_at=datetime.now(UTC).replace(tzinfo=None), ) @@ -168,7 +153,7 @@ class WorkflowCycleManager: workflow_run_id: str, total_tokens: int, total_steps: int, - status: WorkflowRunStatus, + status: WorkflowExecutionStatus, error_message: str, conversation_id: Optional[str] = None, trace_manager: Optional[TraceQueueManager] = None, @@ -185,7 +170,7 @@ class WorkflowCycleManager: # Use the instance repository to find running executions for a workflow run running_node_executions = self._workflow_node_execution_repository.get_running_executions( - workflow_run_id=workflow_execution.id + workflow_run_id=workflow_execution.id_ ) # Update the domain models @@ -193,7 +178,7 @@ class WorkflowCycleManager: for node_execution in running_node_executions: if node_execution.node_execution_id: # Update the domain model - node_execution.status = NodeExecutionStatus.FAILED + node_execution.status = WorkflowNodeExecutionStatus.FAILED node_execution.error = error_message node_execution.finished_at = now node_execution.elapsed_time = (now - node_execution.created_at).total_seconds() @@ -233,14 +218,14 @@ class WorkflowCycleManager: domain_execution = NodeExecution( id=str(uuid4()), workflow_id=workflow_execution.workflow_id, - workflow_run_id=workflow_execution.id, + workflow_run_id=workflow_execution.id_, predecessor_node_id=event.predecessor_node_id, index=event.node_run_index, node_execution_id=event.node_execution_id, node_id=event.node_id, node_type=event.node_type, title=event.node_data.title, - status=NodeExecutionStatus.RUNNING, + status=WorkflowNodeExecutionStatus.RUNNING, metadata=metadata, created_at=created_at, ) @@ -271,7 +256,7 @@ class WorkflowCycleManager: elapsed_time = (finished_at - event.start_at).total_seconds() # Update domain model - domain_execution.status = NodeExecutionStatus.SUCCEEDED + domain_execution.status = WorkflowNodeExecutionStatus.SUCCEEDED domain_execution.update_from_mapping( inputs=inputs, process_data=process_data, outputs=outputs, metadata=execution_metadata_dict ) @@ -317,9 +302,9 @@ class WorkflowCycleManager: # Update domain model domain_execution.status = ( - NodeExecutionStatus.FAILED + WorkflowNodeExecutionStatus.FAILED if not isinstance(event, QueueNodeExceptionEvent) - else NodeExecutionStatus.EXCEPTION + else WorkflowNodeExecutionStatus.EXCEPTION ) domain_execution.error = event.error domain_execution.update_from_mapping( @@ -362,13 +347,13 @@ class WorkflowCycleManager: domain_execution = NodeExecution( id=str(uuid4()), workflow_id=workflow_execution.workflow_id, - workflow_run_id=workflow_execution.id, + workflow_run_id=workflow_execution.id_, predecessor_node_id=event.predecessor_node_id, node_execution_id=event.node_execution_id, node_id=event.node_id, node_type=event.node_type, title=event.node_data.title, - status=NodeExecutionStatus.RETRY, + status=WorkflowNodeExecutionStatus.RETRY, created_at=created_at, finished_at=finished_at, elapsed_time=elapsed_time, diff --git a/api/models/__init__.py b/api/models/__init__.py index f652449e98..13eab226b7 100644 --- a/api/models/__init__.py +++ b/api/models/__init__.py @@ -85,10 +85,8 @@ from .workflow import ( WorkflowAppLog, WorkflowAppLogCreatedFrom, WorkflowNodeExecution, - WorkflowNodeExecutionStatus, WorkflowNodeExecutionTriggeredFrom, WorkflowRun, - WorkflowRunStatus, WorkflowType, ) @@ -100,14 +98,14 @@ __all__ = [ "AccountStatus", "ApiRequest", "ApiToken", - "ApiToolProvider", # Added + "ApiToolProvider", "App", "AppAnnotationHitHistory", "AppAnnotationSetting", "AppDatasetJoin", "AppMode", "AppModelConfig", - "BuiltinToolProvider", # Added + "BuiltinToolProvider", "CeleryTask", "CeleryTaskSet", "Conversation", @@ -172,10 +170,8 @@ __all__ = [ "WorkflowAppLog", "WorkflowAppLogCreatedFrom", "WorkflowNodeExecution", - "WorkflowNodeExecutionStatus", "WorkflowNodeExecutionTriggeredFrom", "WorkflowRun", - "WorkflowRunStatus", "WorkflowRunTriggeredFrom", "WorkflowToolProvider", "WorkflowType", diff --git a/api/models/model.py b/api/models/model.py index 92a5c0d121..229e77134e 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Any, Literal, Optional, cast from core.plugin.entities.plugin import GenericProviderID from core.tools.entities.tool_entities import ToolProviderType from core.tools.signature import sign_tool_file +from core.workflow.entities.workflow_execution import WorkflowExecutionStatus from services.plugin.plugin_service import PluginService if TYPE_CHECKING: @@ -31,7 +32,6 @@ from .base import Base from .engine import db from .enums import CreatorUserRole from .types import StringUUID -from .workflow import WorkflowRunStatus if TYPE_CHECKING: from .workflow import Workflow @@ -794,22 +794,22 @@ class Conversation(Base): def status_count(self): messages = db.session.query(Message).filter(Message.conversation_id == self.id).all() status_counts = { - WorkflowRunStatus.RUNNING: 0, - WorkflowRunStatus.SUCCEEDED: 0, - WorkflowRunStatus.FAILED: 0, - WorkflowRunStatus.STOPPED: 0, - WorkflowRunStatus.PARTIAL_SUCCEEDED: 0, + WorkflowExecutionStatus.RUNNING: 0, + WorkflowExecutionStatus.SUCCEEDED: 0, + WorkflowExecutionStatus.FAILED: 0, + WorkflowExecutionStatus.STOPPED: 0, + WorkflowExecutionStatus.PARTIAL_SUCCEEDED: 0, } for message in messages: if message.workflow_run: - status_counts[WorkflowRunStatus(message.workflow_run.status)] += 1 + status_counts[WorkflowExecutionStatus(message.workflow_run.status)] += 1 return ( { - "success": status_counts[WorkflowRunStatus.SUCCEEDED], - "failed": status_counts[WorkflowRunStatus.FAILED], - "partial_success": status_counts[WorkflowRunStatus.PARTIAL_SUCCEEDED], + "success": status_counts[WorkflowExecutionStatus.SUCCEEDED], + "failed": status_counts[WorkflowExecutionStatus.FAILED], + "partial_success": status_counts[WorkflowExecutionStatus.PARTIAL_SUCCEEDED], } if messages else None diff --git a/api/models/workflow.py b/api/models/workflow.py index ae341dd1b5..6a162d52d4 100644 --- a/api/models/workflow.py +++ b/api/models/workflow.py @@ -377,18 +377,6 @@ class Workflow(Base): ) -class WorkflowRunStatus(StrEnum): - """ - Workflow Run Status Enum - """ - - RUNNING = "running" - SUCCEEDED = "succeeded" - FAILED = "failed" - STOPPED = "stopped" - PARTIAL_SUCCEEDED = "partial-succeeded" - - class WorkflowRun(Base): """ Workflow Run @@ -553,18 +541,6 @@ class WorkflowNodeExecutionTriggeredFrom(StrEnum): WORKFLOW_RUN = "workflow-run" -class WorkflowNodeExecutionStatus(StrEnum): - """ - Workflow Node Execution Status Enum - """ - - RUNNING = "running" - SUCCEEDED = "succeeded" - FAILED = "failed" - EXCEPTION = "exception" - RETRY = "retry" - - class WorkflowNodeExecution(Base): """ Workflow Node Execution diff --git a/api/pytest.ini b/api/pytest.ini index 618e921825..eb49619481 100644 --- a/api/pytest.ini +++ b/api/pytest.ini @@ -1,5 +1,4 @@ [pytest] -continue-on-collection-errors = true addopts = --cov=./api --cov-report=json --cov-report=xml env = ANTHROPIC_API_KEY = sk-ant-api11-IamNotARealKeyJustForMockTestKawaiiiiiiiiii-NotBaka-ASkksz diff --git a/api/services/workflow_app_service.py b/api/services/workflow_app_service.py index a899ebe278..6b30a70372 100644 --- a/api/services/workflow_app_service.py +++ b/api/services/workflow_app_service.py @@ -4,9 +4,9 @@ from datetime import datetime from sqlalchemy import and_, func, or_, select from sqlalchemy.orm import Session +from core.workflow.entities.workflow_execution import WorkflowExecutionStatus from models import App, EndUser, WorkflowAppLog, WorkflowRun from models.enums import CreatorUserRole -from models.workflow import WorkflowRunStatus class WorkflowAppService: @@ -16,7 +16,7 @@ class WorkflowAppService: session: Session, app_model: App, keyword: str | None = None, - status: WorkflowRunStatus | None = None, + status: WorkflowExecutionStatus | None = None, created_at_before: datetime | None = None, created_at_after: datetime | None = None, page: int = 1, diff --git a/api/services/workflow_run_service.py b/api/services/workflow_run_service.py index 21366a4552..0ad900d758 100644 --- a/api/services/workflow_run_service.py +++ b/api/services/workflow_run_service.py @@ -4,7 +4,7 @@ from typing import Optional import contexts from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.repository.workflow_node_execution_repository import OrderConfig +from core.workflow.repositories.workflow_node_execution_repository import OrderConfig from extensions.ext_database import db from libs.infinite_scroll_pagination import InfiniteScrollPagination from models import ( diff --git a/api/services/workflow_service.py b/api/services/workflow_service.py index 50bb8f40ae..2460aa25a7 100644 --- a/api/services/workflow_service.py +++ b/api/services/workflow_service.py @@ -13,7 +13,7 @@ from core.app.apps.workflow.app_config_manager import WorkflowAppConfigManager from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.variables import Variable from core.workflow.entities.node_entities import NodeRunResult -from core.workflow.entities.node_execution_entities import NodeExecution, NodeExecutionStatus +from core.workflow.entities.workflow_node_execution import NodeExecution, WorkflowNodeExecutionStatus from core.workflow.errors import WorkflowNodeRunFailedError from core.workflow.graph_engine.entities.event import InNodeEvent from core.workflow.nodes import NodeType @@ -31,7 +31,6 @@ from models.tools import WorkflowToolProvider from models.workflow import ( Workflow, WorkflowNodeExecution, - WorkflowNodeExecutionStatus, WorkflowNodeExecutionTriggeredFrom, WorkflowType, ) @@ -404,13 +403,13 @@ class WorkflowService: # Map status from WorkflowNodeExecutionStatus to NodeExecutionStatus if node_run_result.status == WorkflowNodeExecutionStatus.SUCCEEDED: - node_execution.status = NodeExecutionStatus.SUCCEEDED + node_execution.status = WorkflowNodeExecutionStatus.SUCCEEDED elif node_run_result.status == WorkflowNodeExecutionStatus.EXCEPTION: - node_execution.status = NodeExecutionStatus.EXCEPTION + node_execution.status = WorkflowNodeExecutionStatus.EXCEPTION node_execution.error = node_run_result.error else: # Set failed status and error - node_execution.status = NodeExecutionStatus.FAILED + node_execution.status = WorkflowNodeExecutionStatus.FAILED node_execution.error = error return node_execution diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index 4de985ae7c..13d78c2d83 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -8,6 +8,7 @@ import pytest from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams @@ -15,7 +16,7 @@ from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntime from core.workflow.nodes.code.code_node import CodeNode from core.workflow.nodes.code.entities import CodeNodeData from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_code_executor_mock CODE_MAX_STRING_LENGTH = int(getenv("CODE_MAX_STRING_LENGTH", "10000")) diff --git a/api/tests/integration_tests/workflow/nodes/test_llm.py b/api/tests/integration_tests/workflow/nodes/test_llm.py index 777a04bd7f..5fbee266bd 100644 --- a/api/tests/integration_tests/workflow/nodes/test_llm.py +++ b/api/tests/integration_tests/workflow/nodes/test_llm.py @@ -9,6 +9,7 @@ import pytest from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams @@ -17,7 +18,7 @@ from core.workflow.nodes.event import RunCompletedEvent from core.workflow.nodes.llm.node import LLMNode from extensions.ext_database import db from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType from tests.integration_tests.workflow.nodes.__mock.model import get_mocked_fetch_model_config """FOR MOCK FIXTURES, DO NOT REMOVE""" diff --git a/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py b/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py index 5c6bb82024..e89e03ae86 100644 --- a/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py +++ b/api/tests/integration_tests/workflow/nodes/test_parameter_extractor.py @@ -7,6 +7,7 @@ from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom from core.model_runtime.entities import AssistantPromptMessage from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams @@ -17,7 +18,7 @@ from models.enums import UserFrom from tests.integration_tests.workflow.nodes.__mock.model import get_mocked_fetch_model_config """FOR MOCK FIXTURES, DO NOT REMOVE""" -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType from tests.integration_tests.model_runtime.__mock.plugin_daemon import setup_model_mock diff --git a/api/tests/integration_tests/workflow/nodes/test_template_transform.py b/api/tests/integration_tests/workflow/nodes/test_template_transform.py index 51d61a95ea..a5f2677a59 100644 --- a/api/tests/integration_tests/workflow/nodes/test_template_transform.py +++ b/api/tests/integration_tests/workflow/nodes/test_template_transform.py @@ -5,13 +5,14 @@ import pytest from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType from tests.integration_tests.workflow.nodes.__mock.code_executor import setup_code_executor_mock diff --git a/api/tests/integration_tests/workflow/nodes/test_tool.py b/api/tests/integration_tests/workflow/nodes/test_tool.py index 5a569a5983..039beedafe 100644 --- a/api/tests/integration_tests/workflow/nodes/test_tool.py +++ b/api/tests/integration_tests/workflow/nodes/test_tool.py @@ -5,6 +5,7 @@ from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom from core.tools.utils.configuration import ToolParameterConfigurationManager from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams @@ -12,7 +13,7 @@ from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntime from core.workflow.nodes.event.event import RunCompletedEvent from core.workflow.nodes.tool.tool_node import ToolNode from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType def init_tool_node(config: dict): diff --git a/api/tests/unit_tests/core/prompt/test_extract_thread_messages.py b/api/tests/unit_tests/core/prompt/test_extract_thread_messages.py index ba3c1eb5e0..e3e500e310 100644 --- a/api/tests/unit_tests/core/prompt/test_extract_thread_messages.py +++ b/api/tests/unit_tests/core/prompt/test_extract_thread_messages.py @@ -4,7 +4,7 @@ from constants import UUID_NIL from core.prompt.utils.extract_thread_messages import extract_thread_messages -class TestMessage: +class MockMessage: def __init__(self, id, parent_message_id): self.id = id self.parent_message_id = parent_message_id @@ -14,7 +14,7 @@ class TestMessage: def test_extract_thread_messages_single_message(): - messages = [TestMessage(str(uuid4()), UUID_NIL)] + messages = [MockMessage(str(uuid4()), UUID_NIL)] result = extract_thread_messages(messages) assert len(result) == 1 assert result[0] == messages[0] @@ -23,11 +23,11 @@ def test_extract_thread_messages_single_message(): def test_extract_thread_messages_linear_thread(): id1, id2, id3, id4, id5 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) messages = [ - TestMessage(id5, id4), - TestMessage(id4, id3), - TestMessage(id3, id2), - TestMessage(id2, id1), - TestMessage(id1, UUID_NIL), + MockMessage(id5, id4), + MockMessage(id4, id3), + MockMessage(id3, id2), + MockMessage(id2, id1), + MockMessage(id1, UUID_NIL), ] result = extract_thread_messages(messages) assert len(result) == 5 @@ -37,10 +37,10 @@ def test_extract_thread_messages_linear_thread(): def test_extract_thread_messages_branched_thread(): id1, id2, id3, id4 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) messages = [ - TestMessage(id4, id2), - TestMessage(id3, id2), - TestMessage(id2, id1), - TestMessage(id1, UUID_NIL), + MockMessage(id4, id2), + MockMessage(id3, id2), + MockMessage(id2, id1), + MockMessage(id1, UUID_NIL), ] result = extract_thread_messages(messages) assert len(result) == 3 @@ -56,9 +56,9 @@ def test_extract_thread_messages_empty_list(): def test_extract_thread_messages_partially_loaded(): id0, id1, id2, id3 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) messages = [ - TestMessage(id3, id2), - TestMessage(id2, id1), - TestMessage(id1, id0), + MockMessage(id3, id2), + MockMessage(id2, id1), + MockMessage(id1, id0), ] result = extract_thread_messages(messages) assert len(result) == 3 @@ -68,9 +68,9 @@ def test_extract_thread_messages_partially_loaded(): def test_extract_thread_messages_legacy_messages(): id1, id2, id3 = str(uuid4()), str(uuid4()), str(uuid4()) messages = [ - TestMessage(id3, UUID_NIL), - TestMessage(id2, UUID_NIL), - TestMessage(id1, UUID_NIL), + MockMessage(id3, UUID_NIL), + MockMessage(id2, UUID_NIL), + MockMessage(id1, UUID_NIL), ] result = extract_thread_messages(messages) assert len(result) == 3 @@ -80,11 +80,11 @@ def test_extract_thread_messages_legacy_messages(): def test_extract_thread_messages_mixed_with_legacy_messages(): id1, id2, id3, id4, id5 = str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()), str(uuid4()) messages = [ - TestMessage(id5, id4), - TestMessage(id4, id2), - TestMessage(id3, id2), - TestMessage(id2, UUID_NIL), - TestMessage(id1, UUID_NIL), + MockMessage(id5, id4), + MockMessage(id4, id2), + MockMessage(id3, id2), + MockMessage(id2, UUID_NIL), + MockMessage(id1, UUID_NIL), ] result = extract_thread_messages(messages) assert len(result) == 4 diff --git a/api/tests/unit_tests/core/rag/datasource/vdb/milvus/test_milvus.py b/api/tests/unit_tests/core/rag/datasource/vdb/milvus/test_milvus.py index bd414c88f4..48cc8a7e1c 100644 --- a/api/tests/unit_tests/core/rag/datasource/vdb/milvus/test_milvus.py +++ b/api/tests/unit_tests/core/rag/datasource/vdb/milvus/test_milvus.py @@ -1,5 +1,5 @@ import pytest -from pydantic.error_wrappers import ValidationError +from pydantic import ValidationError from core.rag.datasource.vdb.milvus.milvus_vector import MilvusConfig diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py index f3dbd1836b..34c64121af 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py @@ -6,6 +6,7 @@ from flask import Flask from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.event import ( BaseNodeEvent, @@ -25,7 +26,7 @@ from core.workflow.nodes.event import RunCompletedEvent, RunStreamChunkEvent from core.workflow.nodes.llm.node import LLMNode from core.workflow.nodes.question_classifier.question_classifier_node import QuestionClassifierNode from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType @pytest.fixture diff --git a/api/tests/unit_tests/core/workflow/nodes/answer/test_answer.py b/api/tests/unit_tests/core/workflow/nodes/answer/test_answer.py index 0369f3fa44..b7f78d91fa 100644 --- a/api/tests/unit_tests/core/workflow/nodes/answer/test_answer.py +++ b/api/tests/unit_tests/core/workflow/nodes/answer/test_answer.py @@ -4,6 +4,7 @@ from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams @@ -11,7 +12,7 @@ from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntime from core.workflow.nodes.answer.answer_node import AnswerNode from extensions.ext_database import db from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType def test_execute_answer(): diff --git a/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_node.py b/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_node.py index 2073d355f0..7fd32a4826 100644 --- a/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/http_request/test_http_request_node.py @@ -4,6 +4,7 @@ from core.app.entities.app_invoke_entities import InvokeFrom from core.file import File, FileTransferMethod, FileType from core.variables import ArrayFileVariable, FileVariable from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState from core.workflow.nodes.answer import AnswerStreamGenerateRoute from core.workflow.nodes.end import EndStreamParam @@ -15,7 +16,7 @@ from core.workflow.nodes.http_request import ( HttpRequestNodeData, ) from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType def test_http_request_node_binary_file(monkeypatch): diff --git a/api/tests/unit_tests/core/workflow/nodes/iteration/test_iteration.py b/api/tests/unit_tests/core/workflow/nodes/iteration/test_iteration.py index 29bd4d6c6c..6d854c950d 100644 --- a/api/tests/unit_tests/core/workflow/nodes/iteration/test_iteration.py +++ b/api/tests/unit_tests/core/workflow/nodes/iteration/test_iteration.py @@ -5,6 +5,7 @@ from unittest.mock import patch from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams @@ -14,7 +15,7 @@ from core.workflow.nodes.iteration.entities import ErrorHandleMode from core.workflow.nodes.iteration.iteration_node import IterationNode from core.workflow.nodes.template_transform.template_transform_node import TemplateTransformNode from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType def test_run(): diff --git a/api/tests/unit_tests/core/workflow/nodes/test_answer.py b/api/tests/unit_tests/core/workflow/nodes/test_answer.py index 2f0aa28b48..abc822e98b 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_answer.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_answer.py @@ -4,6 +4,7 @@ from unittest.mock import MagicMock from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams @@ -11,7 +12,7 @@ from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntime from core.workflow.nodes.answer.answer_node import AnswerNode from extensions.ext_database import db from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType def test_execute_answer(): diff --git a/api/tests/unit_tests/core/workflow/nodes/test_continue_on_error.py b/api/tests/unit_tests/core/workflow/nodes/test_continue_on_error.py index 111c647d9c..c429ac7dd3 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_continue_on_error.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_continue_on_error.py @@ -2,6 +2,7 @@ from unittest.mock import patch from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.event import ( GraphRunPartialSucceededEvent, @@ -14,7 +15,7 @@ from core.workflow.graph_engine.graph_engine import GraphEngine from core.workflow.nodes.event.event import RunCompletedEvent, RunStreamChunkEvent from core.workflow.nodes.llm.node import LLMNode from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType class ContinueOnErrorTestHelper: diff --git a/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py b/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py index 6d46ea9b89..35d83449c3 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py @@ -7,6 +7,7 @@ from core.file import File, FileTransferMethod from core.variables import ArrayFileSegment from core.variables.variables import StringVariable from core.workflow.entities.node_entities import NodeRunResult +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.document_extractor import DocumentExtractorNode, DocumentExtractorNodeData from core.workflow.nodes.document_extractor.node import ( _extract_text_from_docx, @@ -15,7 +16,6 @@ from core.workflow.nodes.document_extractor.node import ( _extract_text_from_plain_text, ) from core.workflow.nodes.enums import NodeType -from models.workflow import WorkflowNodeExecutionStatus @pytest.fixture diff --git a/api/tests/unit_tests/core/workflow/nodes/test_if_else.py b/api/tests/unit_tests/core/workflow/nodes/test_if_else.py index 41e2c5d484..c4e411f9d6 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_if_else.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_if_else.py @@ -6,6 +6,7 @@ from core.app.entities.app_invoke_entities import InvokeFrom from core.file import File, FileTransferMethod, FileType from core.variables import ArrayFileSegment from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams @@ -15,7 +16,7 @@ from core.workflow.nodes.if_else.if_else_node import IfElseNode from core.workflow.utils.condition.entities import Condition, SubCondition, SubVariableCondition from extensions.ext_database import db from models.enums import UserFrom -from models.workflow import WorkflowNodeExecutionStatus, WorkflowType +from models.workflow import WorkflowType def test_execute_if_else_result_true(): diff --git a/api/tests/unit_tests/core/workflow/nodes/test_list_operator.py b/api/tests/unit_tests/core/workflow/nodes/test_list_operator.py index 36116d3540..77d42e2692 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_list_operator.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_list_operator.py @@ -4,6 +4,7 @@ import pytest from core.file import File, FileTransferMethod, FileType from core.variables import ArrayFileSegment +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.nodes.list_operator.entities import ( ExtractConfig, FilterBy, @@ -14,7 +15,6 @@ from core.workflow.nodes.list_operator.entities import ( ) from core.workflow.nodes.list_operator.exc import InvalidKeyError from core.workflow.nodes.list_operator.node import ListOperatorNode, _get_file_extract_string_func -from models.workflow import WorkflowNodeExecutionStatus @pytest.fixture diff --git a/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py b/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py index f593510830..e121f6338c 100644 --- a/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/tool/test_tool_node.py @@ -7,6 +7,7 @@ from core.tools.entities.tool_entities import ToolInvokeMessage, ToolProviderTyp from core.tools.errors import ToolInvokeError from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.graph_engine import Graph, GraphInitParams, GraphRuntimeState from core.workflow.nodes.answer import AnswerStreamGenerateRoute from core.workflow.nodes.end import EndStreamParam @@ -14,7 +15,7 @@ from core.workflow.nodes.enums import ErrorStrategy from core.workflow.nodes.event import RunCompletedEvent from core.workflow.nodes.tool import ToolNode from core.workflow.nodes.tool.entities import ToolNodeData -from models import UserFrom, WorkflowNodeExecutionStatus, WorkflowType +from models import UserFrom, WorkflowType def _create_tool_node(): diff --git a/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py b/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py index 9c955fc086..a5574d309b 100644 --- a/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py +++ b/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py @@ -12,21 +12,20 @@ from core.app.entities.queue_entities import ( QueueNodeStartedEvent, QueueNodeSucceededEvent, ) -from core.workflow.entities.node_entities import NodeRunMetadataKey -from core.workflow.entities.node_execution_entities import NodeExecution, NodeExecutionStatus -from core.workflow.entities.workflow_execution_entities import WorkflowExecution, WorkflowExecutionStatus, WorkflowType +from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType +from core.workflow.entities.workflow_node_execution import ( + NodeExecution, + NodeRunMetadataKey, + WorkflowNodeExecutionStatus, +) from core.workflow.enums import SystemVariableKey from core.workflow.nodes import NodeType -from core.workflow.repository.workflow_execution_repository import WorkflowExecutionRepository -from core.workflow.repository.workflow_node_execution_repository import WorkflowNodeExecutionRepository -from core.workflow.workflow_cycle_manager import WorkflowCycleManager +from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository +from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository +from core.workflow.workflow_cycle_manager import CycleManagerWorkflowInfo, WorkflowCycleManager from models.enums import CreatorUserRole from models.model import AppMode -from models.workflow import ( - Workflow, - WorkflowRun, - WorkflowRunStatus, -) +from models.workflow import Workflow, WorkflowRun @pytest.fixture @@ -93,16 +92,38 @@ def mock_workflow_execution_repository(): return repo +@pytest.fixture +def real_workflow_entity(): + return CycleManagerWorkflowInfo( + workflow_id="test-workflow-id", # Matches ID used in other fixtures + workflow_type=WorkflowType.CHAT, + version="1.0.0", + graph_data={ + "nodes": [ + { + "id": "node1", + "type": "chat", # NodeType is a string enum + "name": "Chat Node", + "data": {"model": "gpt-3.5-turbo", "prompt": "test prompt"}, + } + ], + "edges": [], + }, + ) + + @pytest.fixture def workflow_cycle_manager( real_app_generate_entity, real_workflow_system_variables, mock_workflow_execution_repository, mock_node_execution_repository, + real_workflow_entity, ): return WorkflowCycleManager( application_generate_entity=real_app_generate_entity, workflow_system_variables=real_workflow_system_variables, + workflow_info=real_workflow_entity, workflow_execution_repository=mock_workflow_execution_repository, workflow_node_execution_repository=mock_node_execution_repository, ) @@ -148,7 +169,7 @@ def real_workflow_run(): workflow_run.version = "1.0" workflow_run.graph = json.dumps({"nodes": [], "edges": []}) workflow_run.inputs = json.dumps({"query": "test query"}) - workflow_run.status = WorkflowRunStatus.RUNNING + workflow_run.status = WorkflowExecutionStatus.RUNNING workflow_run.outputs = json.dumps({"answer": "test answer"}) workflow_run.created_by_role = CreatorUserRole.ACCOUNT workflow_run.created_by = "test-user-id" @@ -171,20 +192,13 @@ def test_init( assert workflow_cycle_manager._workflow_node_execution_repository == mock_node_execution_repository -def test_handle_workflow_run_start(workflow_cycle_manager, mock_session, real_workflow): +def test_handle_workflow_run_start(workflow_cycle_manager): """Test handle_workflow_run_start method""" - # Mock session.scalar to return the workflow and max sequence - mock_session.scalar.side_effect = [real_workflow, 5] - # Call the method - workflow_execution = workflow_cycle_manager.handle_workflow_run_start( - session=mock_session, - workflow_id="test-workflow-id", - ) + workflow_execution = workflow_cycle_manager.handle_workflow_run_start() # Verify the result - assert workflow_execution.workflow_id == real_workflow.id - assert workflow_execution.sequence_number == 6 # max_sequence + 1 + assert workflow_execution.workflow_id == "test-workflow-id" # Verify the workflow_execution_repository.save was called workflow_cycle_manager._workflow_execution_repository.save.assert_called_once_with(workflow_execution) @@ -195,11 +209,10 @@ def test_handle_workflow_run_success(workflow_cycle_manager, mock_workflow_execu # Create a real WorkflowExecution workflow_execution = WorkflowExecution( - id="test-workflow-run-id", + id_="test-workflow-run-id", workflow_id="test-workflow-id", workflow_version="1.0", - sequence_number=1, - type=WorkflowType.CHAT, + workflow_type=WorkflowType.CHAT, graph={"nodes": [], "edges": []}, inputs={"query": "test query"}, started_at=datetime.now(UTC).replace(tzinfo=None), @@ -230,11 +243,10 @@ def test_handle_workflow_run_failed(workflow_cycle_manager, mock_workflow_execut # Create a real WorkflowExecution workflow_execution = WorkflowExecution( - id="test-workflow-run-id", + id_="test-workflow-run-id", workflow_id="test-workflow-id", workflow_version="1.0", - sequence_number=1, - type=WorkflowType.CHAT, + workflow_type=WorkflowType.CHAT, graph={"nodes": [], "edges": []}, inputs={"query": "test query"}, started_at=datetime.now(UTC).replace(tzinfo=None), @@ -251,13 +263,13 @@ def test_handle_workflow_run_failed(workflow_cycle_manager, mock_workflow_execut workflow_run_id="test-workflow-run-id", total_tokens=50, total_steps=3, - status=WorkflowRunStatus.FAILED, + status=WorkflowExecutionStatus.FAILED, error_message="Test error message", ) # Verify the result assert result == workflow_execution - assert result.status == WorkflowExecutionStatus(WorkflowRunStatus.FAILED.value) + assert result.status == WorkflowExecutionStatus.FAILED assert result.error_message == "Test error message" assert result.total_tokens == 50 assert result.total_steps == 3 @@ -269,11 +281,10 @@ def test_handle_node_execution_start(workflow_cycle_manager, mock_workflow_execu # Create a real WorkflowExecution workflow_execution = WorkflowExecution( - id="test-workflow-execution-id", + id_="test-workflow-execution-id", workflow_id="test-workflow-id", workflow_version="1.0", - sequence_number=1, - type=WorkflowType.CHAT, + workflow_type=WorkflowType.CHAT, graph={"nodes": [], "edges": []}, inputs={"query": "test query"}, started_at=datetime.now(UTC).replace(tzinfo=None), @@ -301,18 +312,18 @@ def test_handle_node_execution_start(workflow_cycle_manager, mock_workflow_execu # Call the method result = workflow_cycle_manager.handle_node_execution_start( - workflow_execution_id=workflow_execution.id, + workflow_execution_id=workflow_execution.id_, event=event, ) # Verify the result assert result.workflow_id == workflow_execution.workflow_id - assert result.workflow_run_id == workflow_execution.id + assert result.workflow_run_id == workflow_execution.id_ assert result.node_execution_id == event.node_execution_id assert result.node_id == event.node_id assert result.node_type == event.node_type assert result.title == event.node_data.title - assert result.status == NodeExecutionStatus.RUNNING + assert result.status == WorkflowNodeExecutionStatus.RUNNING # Verify save was called workflow_cycle_manager._workflow_node_execution_repository.save.assert_called_once_with(result) @@ -323,11 +334,10 @@ def test_get_workflow_execution_or_raise_error(workflow_cycle_manager, mock_work # Create a real WorkflowExecution workflow_execution = WorkflowExecution( - id="test-workflow-run-id", + id_="test-workflow-run-id", workflow_id="test-workflow-id", workflow_version="1.0", - sequence_number=1, - type=WorkflowType.CHAT, + workflow_type=WorkflowType.CHAT, graph={"nodes": [], "edges": []}, inputs={"query": "test query"}, started_at=datetime.now(UTC).replace(tzinfo=None), @@ -385,7 +395,7 @@ def test_handle_workflow_node_execution_success(workflow_cycle_manager): # Verify the result assert result == node_execution - assert result.status == NodeExecutionStatus.SUCCEEDED + assert result.status == WorkflowNodeExecutionStatus.SUCCEEDED # Verify save was called workflow_cycle_manager._workflow_node_execution_repository.save.assert_called_once_with(node_execution) @@ -396,11 +406,10 @@ def test_handle_workflow_run_partial_success(workflow_cycle_manager, mock_workfl # Create a real WorkflowExecution workflow_execution = WorkflowExecution( - id="test-workflow-run-id", + id_="test-workflow-run-id", workflow_id="test-workflow-id", workflow_version="1.0", - sequence_number=1, - type=WorkflowType.CHAT, + workflow_type=WorkflowType.CHAT, graph={"nodes": [], "edges": []}, inputs={"query": "test query"}, started_at=datetime.now(UTC).replace(tzinfo=None), @@ -464,7 +473,7 @@ def test_handle_workflow_node_execution_failed(workflow_cycle_manager): # Verify the result assert result == node_execution - assert result.status == NodeExecutionStatus.FAILED + assert result.status == WorkflowNodeExecutionStatus.FAILED assert result.error == "Test error message" # Verify save was called diff --git a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py index 7c5020db02..f3cdfd135b 100644 --- a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py +++ b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py @@ -13,12 +13,15 @@ from sqlalchemy.orm import Session, sessionmaker from core.model_runtime.utils.encoders import jsonable_encoder from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.node_entities import NodeRunMetadataKey -from core.workflow.entities.node_execution_entities import NodeExecution, NodeExecutionStatus +from core.workflow.entities.workflow_node_execution import ( + NodeExecution, + NodeRunMetadataKey, + WorkflowNodeExecutionStatus, +) from core.workflow.nodes.enums import NodeType -from core.workflow.repository.workflow_node_execution_repository import OrderConfig +from core.workflow.repositories.workflow_node_execution_repository import OrderConfig from models.account import Account, Tenant -from models.workflow import WorkflowNodeExecution, WorkflowNodeExecutionStatus, WorkflowNodeExecutionTriggeredFrom +from models.workflow import WorkflowNodeExecution, WorkflowNodeExecutionTriggeredFrom def configure_mock_execution(mock_execution): @@ -297,7 +300,7 @@ def test_to_db_model(repository): inputs={"input_key": "input_value"}, process_data={"process_key": "process_value"}, outputs={"output_key": "output_value"}, - status=NodeExecutionStatus.RUNNING, + status=WorkflowNodeExecutionStatus.RUNNING, error=None, elapsed_time=1.5, metadata={NodeRunMetadataKey.TOTAL_TOKENS: 100, NodeRunMetadataKey.TOTAL_PRICE: Decimal("0.0")}, @@ -388,7 +391,7 @@ def test_to_domain_model(repository): assert domain_model.inputs == inputs_dict assert domain_model.process_data == process_data_dict assert domain_model.outputs == outputs_dict - assert domain_model.status == NodeExecutionStatus(db_model.status) + assert domain_model.status == WorkflowNodeExecutionStatus(db_model.status) assert domain_model.error == db_model.error assert domain_model.elapsed_time == db_model.elapsed_time assert domain_model.metadata == metadata_dict From 32e779eef3d90d1f8ff0e96adb420ad2337122b1 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 04:47:56 +0800 Subject: [PATCH 03/73] refactor(workflow): Rename NodeRunMetadataKey to WorkflowNodeExecutionMetadataKey (#20457) Signed-off-by: -LAN- --- .../common/workflow_response_converter.py | 12 ++--- api/core/app/apps/workflow_app_runner.py | 4 +- api/core/app/entities/queue_entities.py | 14 +++--- api/core/app/entities/task_entities.py | 6 +-- .../ops/langsmith_trace/langsmith_trace.py | 4 +- api/core/ops/opik_trace/opik_trace.py | 4 +- api/core/ops/weave_trace/weave_trace.py | 4 +- ...hemy_workflow_node_execution_repository.py | 8 ++-- api/core/workflow/entities/node_entities.py | 4 +- .../entities/workflow_node_execution.py | 8 ++-- .../workflow/graph_engine/graph_engine.py | 24 ++++++---- .../nodes/iteration/iteration_node.py | 14 +++--- api/core/workflow/nodes/llm/node.py | 8 ++-- api/core/workflow/nodes/loop/loop_node.py | 46 +++++++++++-------- .../parameter_extractor_node.py | 8 ++-- .../question_classifier_node.py | 14 +++--- api/core/workflow/nodes/tool/tool_node.py | 16 +++---- api/core/workflow/workflow_cycle_manager.py | 20 ++++---- .../graph_engine/test_graph_engine.py | 20 ++++---- .../workflow/nodes/test_continue_on_error.py | 8 ++-- .../workflow/test_workflow_cycle_manager.py | 12 ++--- .../test_sqlalchemy_repository.py | 15 +++--- 22 files changed, 145 insertions(+), 128 deletions(-) diff --git a/api/core/app/apps/common/workflow_response_converter.py b/api/core/app/apps/common/workflow_response_converter.py index 6df25b20e3..8f8e429f0c 100644 --- a/api/core/app/apps/common/workflow_response_converter.py +++ b/api/core/app/apps/common/workflow_response_converter.py @@ -147,12 +147,12 @@ class WorkflowResponseConverter: ) -> Optional[NodeStartStreamResponse]: if workflow_node_execution.node_type in {NodeType.ITERATION, NodeType.LOOP}: return None - if not workflow_node_execution.workflow_run_id: + if not workflow_node_execution.workflow_execution_id: return None response = NodeStartStreamResponse( task_id=task_id, - workflow_run_id=workflow_node_execution.workflow_run_id, + workflow_run_id=workflow_node_execution.workflow_execution_id, data=NodeStartStreamResponse.Data( id=workflow_node_execution.id, node_id=workflow_node_execution.node_id, @@ -197,14 +197,14 @@ class WorkflowResponseConverter: ) -> Optional[NodeFinishStreamResponse]: if workflow_node_execution.node_type in {NodeType.ITERATION, NodeType.LOOP}: return None - if not workflow_node_execution.workflow_run_id: + if not workflow_node_execution.workflow_execution_id: return None if not workflow_node_execution.finished_at: return None return NodeFinishStreamResponse( task_id=task_id, - workflow_run_id=workflow_node_execution.workflow_run_id, + workflow_run_id=workflow_node_execution.workflow_execution_id, data=NodeFinishStreamResponse.Data( id=workflow_node_execution.id, node_id=workflow_node_execution.node_id, @@ -240,14 +240,14 @@ class WorkflowResponseConverter: ) -> Optional[Union[NodeRetryStreamResponse, NodeFinishStreamResponse]]: if workflow_node_execution.node_type in {NodeType.ITERATION, NodeType.LOOP}: return None - if not workflow_node_execution.workflow_run_id: + if not workflow_node_execution.workflow_execution_id: return None if not workflow_node_execution.finished_at: return None return NodeRetryStreamResponse( task_id=task_id, - workflow_run_id=workflow_node_execution.workflow_run_id, + workflow_run_id=workflow_node_execution.workflow_execution_id, data=NodeRetryStreamResponse.Data( id=workflow_node_execution.id, node_id=workflow_node_execution.node_id, diff --git a/api/core/app/apps/workflow_app_runner.py b/api/core/app/apps/workflow_app_runner.py index 613bd8e8fc..facc24b4ca 100644 --- a/api/core/app/apps/workflow_app_runner.py +++ b/api/core/app/apps/workflow_app_runner.py @@ -30,7 +30,7 @@ from core.app.entities.queue_entities import ( QueueWorkflowSucceededEvent, ) from core.workflow.entities.variable_pool import VariablePool -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.graph_engine.entities.event import ( AgentLogEvent, GraphEngineEvent, @@ -295,7 +295,7 @@ class WorkflowBasedAppRunner(AppRunner): inputs: Mapping[str, Any] | None = {} process_data: Mapping[str, Any] | None = {} outputs: Mapping[str, Any] | None = {} - execution_metadata: Mapping[NodeRunMetadataKey, Any] | None = {} + execution_metadata: Mapping[WorkflowNodeExecutionMetadataKey, Any] | None = {} if node_run_result: inputs = node_run_result.inputs process_data = node_run_result.process_data diff --git a/api/core/app/entities/queue_entities.py b/api/core/app/entities/queue_entities.py index e4ff123134..bc8573013a 100644 --- a/api/core/app/entities/queue_entities.py +++ b/api/core/app/entities/queue_entities.py @@ -7,7 +7,7 @@ from pydantic import BaseModel from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk from core.workflow.entities.node_entities import AgentNodeStrategyInit -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState from core.workflow.nodes import NodeType from core.workflow.nodes.base import BaseNodeData @@ -413,7 +413,7 @@ class QueueNodeSucceededEvent(AppQueueEvent): inputs: Optional[Mapping[str, Any]] = None process_data: Optional[Mapping[str, Any]] = None outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None + execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None error: Optional[str] = None """single iteration duration map""" @@ -447,7 +447,7 @@ class QueueNodeRetryEvent(QueueNodeStartedEvent): inputs: Optional[Mapping[str, Any]] = None process_data: Optional[Mapping[str, Any]] = None outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None + execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None error: str retry_index: int # retry index @@ -481,7 +481,7 @@ class QueueNodeInIterationFailedEvent(AppQueueEvent): inputs: Optional[Mapping[str, Any]] = None process_data: Optional[Mapping[str, Any]] = None outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None + execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None error: str @@ -514,7 +514,7 @@ class QueueNodeInLoopFailedEvent(AppQueueEvent): inputs: Optional[Mapping[str, Any]] = None process_data: Optional[Mapping[str, Any]] = None outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None + execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None error: str @@ -547,7 +547,7 @@ class QueueNodeExceptionEvent(AppQueueEvent): inputs: Optional[Mapping[str, Any]] = None process_data: Optional[Mapping[str, Any]] = None outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None + execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None error: str @@ -580,7 +580,7 @@ class QueueNodeFailedEvent(AppQueueEvent): inputs: Optional[Mapping[str, Any]] = None process_data: Optional[Mapping[str, Any]] = None outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None + execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None error: str diff --git a/api/core/app/entities/task_entities.py b/api/core/app/entities/task_entities.py index 39b530cdfe..70748b085d 100644 --- a/api/core/app/entities/task_entities.py +++ b/api/core/app/entities/task_entities.py @@ -7,7 +7,7 @@ from pydantic import BaseModel, ConfigDict from core.model_runtime.entities.llm_entities import LLMResult from core.model_runtime.utils.encoders import jsonable_encoder from core.workflow.entities.node_entities import AgentNodeStrategyInit -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus class TaskState(BaseModel): @@ -305,7 +305,7 @@ class NodeFinishStreamResponse(StreamResponse): status: str error: Optional[str] = None elapsed_time: float - execution_metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None + execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None created_at: int finished_at: int files: Optional[Sequence[Mapping[str, Any]]] = [] @@ -374,7 +374,7 @@ class NodeRetryStreamResponse(StreamResponse): status: str error: Optional[str] = None elapsed_time: float - execution_metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None + execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None created_at: int finished_at: int files: Optional[Sequence[Mapping[str, Any]]] = [] diff --git a/api/core/ops/langsmith_trace/langsmith_trace.py b/api/core/ops/langsmith_trace/langsmith_trace.py index 43b866e1af..e4183ea1e2 100644 --- a/api/core/ops/langsmith_trace/langsmith_trace.py +++ b/api/core/ops/langsmith_trace/langsmith_trace.py @@ -28,7 +28,7 @@ from core.ops.langsmith_trace.entities.langsmith_trace_entity import ( ) from core.ops.utils import filter_none_values, generate_dotted_order from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom @@ -185,7 +185,7 @@ class LangSmithDataTrace(BaseTraceInstance): finished_at = created_at + timedelta(seconds=elapsed_time) execution_metadata = node_execution.metadata if node_execution.metadata else {} - node_total_tokens = execution_metadata.get(NodeRunMetadataKey.TOTAL_TOKENS) or 0 + node_total_tokens = execution_metadata.get(WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS) or 0 metadata = {str(key): value for key, value in execution_metadata.items()} metadata.update( { diff --git a/api/core/ops/opik_trace/opik_trace.py b/api/core/ops/opik_trace/opik_trace.py index 7d68dca831..f7a4464267 100644 --- a/api/core/ops/opik_trace/opik_trace.py +++ b/api/core/ops/opik_trace/opik_trace.py @@ -22,7 +22,7 @@ from core.ops.entities.trace_entity import ( WorkflowTraceInfo, ) from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom @@ -246,7 +246,7 @@ class OpikDataTrace(BaseTraceInstance): parent_span_id = trace_info.workflow_app_log_id or trace_info.workflow_run_id if not total_tokens: - total_tokens = execution_metadata.get(NodeRunMetadataKey.TOTAL_TOKENS) or 0 + total_tokens = execution_metadata.get(WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS) or 0 span_data = { "trace_id": opik_trace_id, diff --git a/api/core/ops/weave_trace/weave_trace.py b/api/core/ops/weave_trace/weave_trace.py index d1bd97176e..b12380be47 100644 --- a/api/core/ops/weave_trace/weave_trace.py +++ b/api/core/ops/weave_trace/weave_trace.py @@ -23,7 +23,7 @@ from core.ops.entities.trace_entity import ( ) from core.ops.weave_trace.entities.weave_trace_entity import WeaveTraceModel from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom @@ -179,7 +179,7 @@ class WeaveDataTrace(BaseTraceInstance): finished_at = created_at + timedelta(seconds=elapsed_time) execution_metadata = node_execution.metadata if node_execution.metadata else {} - node_total_tokens = execution_metadata.get(NodeRunMetadataKey.TOTAL_TOKENS) or 0 + node_total_tokens = execution_metadata.get(WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS) or 0 attributes = {str(k): v for k, v in execution_metadata.items()} attributes.update( { diff --git a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py index ee4465db5d..e8a84d58ad 100644 --- a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py +++ b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py @@ -14,7 +14,7 @@ from sqlalchemy.orm import sessionmaker from core.model_runtime.utils.encoders import jsonable_encoder from core.workflow.entities.workflow_node_execution import ( NodeExecution, - NodeRunMetadataKey, + WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) from core.workflow.nodes.enums import NodeType @@ -102,7 +102,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) inputs = db_model.inputs_dict process_data = db_model.process_data_dict outputs = db_model.outputs_dict - metadata = {NodeRunMetadataKey(k): v for k, v in db_model.execution_metadata_dict.items()} + metadata = {WorkflowNodeExecutionMetadataKey(k): v for k, v in db_model.execution_metadata_dict.items()} # Convert status to domain enum status = WorkflowNodeExecutionStatus(db_model.status) @@ -111,7 +111,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) id=db_model.id, node_execution_id=db_model.node_execution_id, workflow_id=db_model.workflow_id, - workflow_run_id=db_model.workflow_run_id, + workflow_execution_id=db_model.workflow_run_id, index=db_model.index, predecessor_node_id=db_model.predecessor_node_id, node_id=db_model.node_id, @@ -153,7 +153,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) db_model.app_id = self._app_id db_model.workflow_id = domain_model.workflow_id db_model.triggered_from = self._triggered_from - db_model.workflow_run_id = domain_model.workflow_run_id + db_model.workflow_run_id = domain_model.workflow_execution_id db_model.index = domain_model.index db_model.predecessor_node_id = domain_model.predecessor_node_id db_model.node_execution_id = domain_model.node_execution_id diff --git a/api/core/workflow/entities/node_entities.py b/api/core/workflow/entities/node_entities.py index 6d01028ffc..687ec8e47c 100644 --- a/api/core/workflow/entities/node_entities.py +++ b/api/core/workflow/entities/node_entities.py @@ -4,7 +4,7 @@ from typing import Any, Optional from pydantic import BaseModel from core.model_runtime.entities.llm_entities import LLMUsage -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus class NodeRunResult(BaseModel): @@ -17,7 +17,7 @@ class NodeRunResult(BaseModel): inputs: Optional[Mapping[str, Any]] = None # node inputs process_data: Optional[Mapping[str, Any]] = None # process data outputs: Optional[Mapping[str, Any]] = None # node outputs - metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None # node metadata + metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None # node metadata llm_usage: Optional[LLMUsage] = None # llm usage edge_source_handle: Optional[str] = None # source handle id of node with multiple branches diff --git a/api/core/workflow/entities/workflow_node_execution.py b/api/core/workflow/entities/workflow_node_execution.py index dccb6b1539..8e19fea43f 100644 --- a/api/core/workflow/entities/workflow_node_execution.py +++ b/api/core/workflow/entities/workflow_node_execution.py @@ -16,7 +16,7 @@ from pydantic import BaseModel, Field from core.workflow.nodes.enums import NodeType -class NodeRunMetadataKey(StrEnum): +class WorkflowNodeExecutionMetadataKey(StrEnum): """ Node Run Metadata Key. """ @@ -70,7 +70,7 @@ class NodeExecution(BaseModel): id: str # Unique identifier for this execution record node_execution_id: Optional[str] = None # Optional secondary ID for cross-referencing workflow_id: str # ID of the workflow this node belongs to - workflow_run_id: Optional[str] = None # ID of the specific workflow run (null for single-step debugging) + workflow_execution_id: Optional[str] = None # ID of the specific workflow run (null for single-step debugging) # Execution positioning and flow index: int # Sequence number for ordering in trace visualization @@ -90,7 +90,7 @@ class NodeExecution(BaseModel): elapsed_time: float = Field(default=0.0) # Time taken for execution in seconds # Additional metadata - metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None # Execution metadata (tokens, cost, etc.) + metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None # Execution metadata (tokens, cost, etc.) # Timing information created_at: datetime # When execution started @@ -101,7 +101,7 @@ class NodeExecution(BaseModel): inputs: Optional[Mapping[str, Any]] = None, process_data: Optional[Mapping[str, Any]] = None, outputs: Optional[Mapping[str, Any]] = None, - metadata: Optional[Mapping[NodeRunMetadataKey, Any]] = None, + metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None, ) -> None: """ Update the model from mappings. diff --git a/api/core/workflow/graph_engine/graph_engine.py b/api/core/workflow/graph_engine/graph_engine.py index 0d71a70971..3eb99fde81 100644 --- a/api/core/workflow/graph_engine/graph_engine.py +++ b/api/core/workflow/graph_engine/graph_engine.py @@ -16,7 +16,7 @@ from core.app.apps.base_app_queue_manager import GenerateTaskStoppedError from core.app.entities.app_invoke_entities import InvokeFrom from core.workflow.entities.node_entities import AgentNodeStrategyInit, NodeRunResult from core.workflow.entities.variable_pool import VariablePool, VariableValue -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from core.workflow.graph_engine.condition_handlers.condition_manager import ConditionManager from core.workflow.graph_engine.entities.event import ( BaseAgentEvent, @@ -760,10 +760,12 @@ class GraphEngine: and node_instance.node_data.error_strategy is ErrorStrategy.FAIL_BRANCH ): run_result.edge_source_handle = FailBranchSourceHandle.SUCCESS - if run_result.metadata and run_result.metadata.get(NodeRunMetadataKey.TOTAL_TOKENS): + if run_result.metadata and run_result.metadata.get( + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS + ): # plus state total_tokens self.graph_runtime_state.total_tokens += int( - run_result.metadata.get(NodeRunMetadataKey.TOTAL_TOKENS) # type: ignore[arg-type] + run_result.metadata.get(WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS) # type: ignore[arg-type] ) if run_result.llm_usage: @@ -786,13 +788,17 @@ class GraphEngine: if parallel_id and parallel_start_node_id: metadata_dict = dict(run_result.metadata) - metadata_dict[NodeRunMetadataKey.PARALLEL_ID] = parallel_id - metadata_dict[NodeRunMetadataKey.PARALLEL_START_NODE_ID] = parallel_start_node_id + metadata_dict[WorkflowNodeExecutionMetadataKey.PARALLEL_ID] = parallel_id + metadata_dict[WorkflowNodeExecutionMetadataKey.PARALLEL_START_NODE_ID] = ( + parallel_start_node_id + ) if parent_parallel_id and parent_parallel_start_node_id: - metadata_dict[NodeRunMetadataKey.PARENT_PARALLEL_ID] = parent_parallel_id - metadata_dict[NodeRunMetadataKey.PARENT_PARALLEL_START_NODE_ID] = ( - parent_parallel_start_node_id + metadata_dict[WorkflowNodeExecutionMetadataKey.PARENT_PARALLEL_ID] = ( + parent_parallel_id ) + metadata_dict[ + WorkflowNodeExecutionMetadataKey.PARENT_PARALLEL_START_NODE_ID + ] = parent_parallel_start_node_id run_result.metadata = metadata_dict yield NodeRunSucceededEvent( @@ -924,7 +930,7 @@ class GraphEngine: "error": error_result.error, "inputs": error_result.inputs, "metadata": { - NodeRunMetadataKey.ERROR_STRATEGY: node_instance.node_data.error_strategy, + WorkflowNodeExecutionMetadataKey.ERROR_STRATEGY: node_instance.node_data.error_strategy, }, } diff --git a/api/core/workflow/nodes/iteration/iteration_node.py b/api/core/workflow/nodes/iteration/iteration_node.py index 7d22a78895..2592823540 100644 --- a/api/core/workflow/nodes/iteration/iteration_node.py +++ b/api/core/workflow/nodes/iteration/iteration_node.py @@ -15,7 +15,7 @@ from core.workflow.entities.node_entities import ( NodeRunResult, ) from core.workflow.entities.variable_pool import VariablePool -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from core.workflow.graph_engine.entities.event import ( BaseGraphEvent, BaseNodeEvent, @@ -248,8 +248,8 @@ class IterationNode(BaseNode[IterationNodeData]): status=WorkflowNodeExecutionStatus.SUCCEEDED, outputs={"output": outputs}, metadata={ - NodeRunMetadataKey.ITERATION_DURATION_MAP: iter_run_map, - NodeRunMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, + WorkflowNodeExecutionMetadataKey.ITERATION_DURATION_MAP: iter_run_map, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, }, ) ) @@ -360,16 +360,16 @@ class IterationNode(BaseNode[IterationNodeData]): event.parallel_mode_run_id = parallel_mode_run_id iter_metadata = { - NodeRunMetadataKey.ITERATION_ID: self.node_id, - NodeRunMetadataKey.ITERATION_INDEX: iter_run_index, + WorkflowNodeExecutionMetadataKey.ITERATION_ID: self.node_id, + WorkflowNodeExecutionMetadataKey.ITERATION_INDEX: iter_run_index, } if parallel_mode_run_id: # for parallel, the specific branch ID is more important than the sequential index - iter_metadata[NodeRunMetadataKey.PARALLEL_MODE_RUN_ID] = parallel_mode_run_id + iter_metadata[WorkflowNodeExecutionMetadataKey.PARALLEL_MODE_RUN_ID] = parallel_mode_run_id if event.route_node_state.node_run_result: current_metadata = event.route_node_state.node_run_result.metadata or {} - if NodeRunMetadataKey.ITERATION_ID not in current_metadata: + if WorkflowNodeExecutionMetadataKey.ITERATION_ID not in current_metadata: event.route_node_state.node_run_result.metadata = {**current_metadata, **iter_metadata} return event diff --git a/api/core/workflow/nodes/llm/node.py b/api/core/workflow/nodes/llm/node.py index ceda0287fd..38e4f7af01 100644 --- a/api/core/workflow/nodes/llm/node.py +++ b/api/core/workflow/nodes/llm/node.py @@ -56,7 +56,7 @@ from core.workflow.constants import SYSTEM_VARIABLE_NODE_ID from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_entities import VariableSelector from core.workflow.entities.variable_pool import VariablePool -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.event import InNodeEvent from core.workflow.nodes.base import BaseNode @@ -267,9 +267,9 @@ class LLMNode(BaseNode[LLMNodeData]): process_data=process_data, outputs=outputs, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: usage.total_tokens, - NodeRunMetadataKey.TOTAL_PRICE: usage.total_price, - NodeRunMetadataKey.CURRENCY: usage.currency, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: usage.total_tokens, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: usage.total_price, + WorkflowNodeExecutionMetadataKey.CURRENCY: usage.currency, }, llm_usage=usage, ) diff --git a/api/core/workflow/nodes/loop/loop_node.py b/api/core/workflow/nodes/loop/loop_node.py index eef63c5a92..fafa205386 100644 --- a/api/core/workflow/nodes/loop/loop_node.py +++ b/api/core/workflow/nodes/loop/loop_node.py @@ -16,7 +16,7 @@ from core.variables import ( StringSegment, ) from core.workflow.entities.node_entities import NodeRunResult -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from core.workflow.graph_engine.entities.event import ( BaseGraphEvent, BaseNodeEvent, @@ -187,10 +187,10 @@ class LoopNode(BaseNode[LoopNodeData]): outputs=self.node_data.outputs, steps=loop_count, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, "completed_reason": "loop_break" if check_break_result else "loop_completed", - NodeRunMetadataKey.LOOP_DURATION_MAP: loop_duration_map, - NodeRunMetadataKey.LOOP_VARIABLE_MAP: single_loop_variable_map, + WorkflowNodeExecutionMetadataKey.LOOP_DURATION_MAP: loop_duration_map, + WorkflowNodeExecutionMetadataKey.LOOP_VARIABLE_MAP: single_loop_variable_map, }, ) @@ -198,9 +198,9 @@ class LoopNode(BaseNode[LoopNodeData]): run_result=NodeRunResult( status=WorkflowNodeExecutionStatus.SUCCEEDED, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, - NodeRunMetadataKey.LOOP_DURATION_MAP: loop_duration_map, - NodeRunMetadataKey.LOOP_VARIABLE_MAP: single_loop_variable_map, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, + WorkflowNodeExecutionMetadataKey.LOOP_DURATION_MAP: loop_duration_map, + WorkflowNodeExecutionMetadataKey.LOOP_VARIABLE_MAP: single_loop_variable_map, }, outputs=self.node_data.outputs, inputs=inputs, @@ -221,8 +221,8 @@ class LoopNode(BaseNode[LoopNodeData]): metadata={ "total_tokens": graph_engine.graph_runtime_state.total_tokens, "completed_reason": "error", - NodeRunMetadataKey.LOOP_DURATION_MAP: loop_duration_map, - NodeRunMetadataKey.LOOP_VARIABLE_MAP: single_loop_variable_map, + WorkflowNodeExecutionMetadataKey.LOOP_DURATION_MAP: loop_duration_map, + WorkflowNodeExecutionMetadataKey.LOOP_VARIABLE_MAP: single_loop_variable_map, }, error=str(e), ) @@ -232,9 +232,9 @@ class LoopNode(BaseNode[LoopNodeData]): status=WorkflowNodeExecutionStatus.FAILED, error=str(e), metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, - NodeRunMetadataKey.LOOP_DURATION_MAP: loop_duration_map, - NodeRunMetadataKey.LOOP_VARIABLE_MAP: single_loop_variable_map, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, + WorkflowNodeExecutionMetadataKey.LOOP_DURATION_MAP: loop_duration_map, + WorkflowNodeExecutionMetadataKey.LOOP_VARIABLE_MAP: single_loop_variable_map, }, ) ) @@ -322,7 +322,9 @@ class LoopNode(BaseNode[LoopNodeData]): inputs=inputs, steps=current_index, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: ( + graph_engine.graph_runtime_state.total_tokens + ), "completed_reason": "error", }, error=event.error, @@ -331,7 +333,11 @@ class LoopNode(BaseNode[LoopNodeData]): run_result=NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, error=event.error, - metadata={NodeRunMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens}, + metadata={ + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: ( + graph_engine.graph_runtime_state.total_tokens + ) + }, ) ) return {"check_break_result": True} @@ -347,7 +353,7 @@ class LoopNode(BaseNode[LoopNodeData]): inputs=inputs, steps=current_index, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens, "completed_reason": "error", }, error=event.error, @@ -356,7 +362,9 @@ class LoopNode(BaseNode[LoopNodeData]): run_result=NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, error=event.error, - metadata={NodeRunMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens}, + metadata={ + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: graph_engine.graph_runtime_state.total_tokens + }, ) ) return {"check_break_result": True} @@ -411,11 +419,11 @@ class LoopNode(BaseNode[LoopNodeData]): metadata = event.route_node_state.node_run_result.metadata if not metadata: metadata = {} - if NodeRunMetadataKey.LOOP_ID not in metadata: + if WorkflowNodeExecutionMetadataKey.LOOP_ID not in metadata: metadata = { **metadata, - NodeRunMetadataKey.LOOP_ID: self.node_id, - NodeRunMetadataKey.LOOP_INDEX: iter_run_index, + WorkflowNodeExecutionMetadataKey.LOOP_ID: self.node_id, + WorkflowNodeExecutionMetadataKey.LOOP_INDEX: iter_run_index, } event.route_node_state.node_run_result.metadata = metadata return event diff --git a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py index 244b15594e..3d13cf7ecd 100644 --- a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py +++ b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py @@ -27,7 +27,7 @@ from core.prompt.simple_prompt_transform import ModelMode from core.prompt.utils.prompt_message_util import PromptMessageUtil from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from core.workflow.nodes.enums import NodeType from core.workflow.nodes.llm import LLMNode, ModelConfig from core.workflow.utils import variable_template_parser @@ -244,9 +244,9 @@ class ParameterExtractorNode(LLMNode): process_data=process_data, outputs={"__is_success": 1 if not error else 0, "__reason": error, **result}, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: usage.total_tokens, - NodeRunMetadataKey.TOTAL_PRICE: usage.total_price, - NodeRunMetadataKey.CURRENCY: usage.currency, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: usage.total_tokens, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: usage.total_price, + WorkflowNodeExecutionMetadataKey.CURRENCY: usage.currency, }, llm_usage=usage, ) diff --git a/api/core/workflow/nodes/question_classifier/question_classifier_node.py b/api/core/workflow/nodes/question_classifier/question_classifier_node.py index 47626e983d..e846b76280 100644 --- a/api/core/workflow/nodes/question_classifier/question_classifier_node.py +++ b/api/core/workflow/nodes/question_classifier/question_classifier_node.py @@ -11,7 +11,7 @@ from core.prompt.advanced_prompt_transform import AdvancedPromptTransform from core.prompt.simple_prompt_transform import ModelMode from core.prompt.utils.prompt_message_util import PromptMessageUtil from core.workflow.entities.node_entities import NodeRunResult -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from core.workflow.nodes.enums import NodeType from core.workflow.nodes.event import ModelInvokeCompletedEvent from core.workflow.nodes.llm import ( @@ -142,9 +142,9 @@ class QuestionClassifierNode(LLMNode): outputs=outputs, edge_source_handle=category_id, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: usage.total_tokens, - NodeRunMetadataKey.TOTAL_PRICE: usage.total_price, - NodeRunMetadataKey.CURRENCY: usage.currency, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: usage.total_tokens, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: usage.total_price, + WorkflowNodeExecutionMetadataKey.CURRENCY: usage.currency, }, llm_usage=usage, ) @@ -154,9 +154,9 @@ class QuestionClassifierNode(LLMNode): inputs=variables, error=str(e), metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: usage.total_tokens, - NodeRunMetadataKey.TOTAL_PRICE: usage.total_price, - NodeRunMetadataKey.CURRENCY: usage.currency, + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: usage.total_tokens, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: usage.total_price, + WorkflowNodeExecutionMetadataKey.CURRENCY: usage.currency, }, llm_usage=usage, ) diff --git a/api/core/workflow/nodes/tool/tool_node.py b/api/core/workflow/nodes/tool/tool_node.py index 077e21ade4..aaecc7b989 100644 --- a/api/core/workflow/nodes/tool/tool_node.py +++ b/api/core/workflow/nodes/tool/tool_node.py @@ -16,7 +16,7 @@ from core.variables.segments import ArrayAnySegment from core.variables.variables import ArrayAnyVariable from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.variable_pool import VariablePool -from core.workflow.entities.workflow_node_execution import NodeRunMetadataKey, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.event import AgentLogEvent from core.workflow.nodes.base import BaseNode @@ -70,7 +70,7 @@ class ToolNode(BaseNode[ToolNodeData]): run_result=NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs={}, - metadata={NodeRunMetadataKey.TOOL_INFO: tool_info}, + metadata={WorkflowNodeExecutionMetadataKey.TOOL_INFO: tool_info}, error=f"Failed to get tool runtime: {str(e)}", error_type=type(e).__name__, ) @@ -110,7 +110,7 @@ class ToolNode(BaseNode[ToolNodeData]): run_result=NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs=parameters_for_log, - metadata={NodeRunMetadataKey.TOOL_INFO: tool_info}, + metadata={WorkflowNodeExecutionMetadataKey.TOOL_INFO: tool_info}, error=f"Failed to invoke tool: {str(e)}", error_type=type(e).__name__, ) @@ -125,7 +125,7 @@ class ToolNode(BaseNode[ToolNodeData]): run_result=NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs=parameters_for_log, - metadata={NodeRunMetadataKey.TOOL_INFO: tool_info}, + metadata={WorkflowNodeExecutionMetadataKey.TOOL_INFO: tool_info}, error=f"Failed to transform tool message: {str(e)}", error_type=type(e).__name__, ) @@ -201,7 +201,7 @@ class ToolNode(BaseNode[ToolNodeData]): json: list[dict] = [] agent_logs: list[AgentLogEvent] = [] - agent_execution_metadata: Mapping[NodeRunMetadataKey, Any] = {} + agent_execution_metadata: Mapping[WorkflowNodeExecutionMetadataKey, Any] = {} variables: dict[str, Any] = {} @@ -274,7 +274,7 @@ class ToolNode(BaseNode[ToolNodeData]): agent_execution_metadata = { key: value for key, value in msg_metadata.items() - if key in NodeRunMetadataKey.__members__.values() + if key in WorkflowNodeExecutionMetadataKey.__members__.values() } json.append(message.message.json_object) elif message.type == ToolInvokeMessage.MessageType.LINK: @@ -366,8 +366,8 @@ class ToolNode(BaseNode[ToolNodeData]): outputs={"text": text, "files": files, "json": json, **variables}, metadata={ **agent_execution_metadata, - NodeRunMetadataKey.TOOL_INFO: tool_info, - NodeRunMetadataKey.AGENT_LOG: agent_logs, + WorkflowNodeExecutionMetadataKey.TOOL_INFO: tool_info, + WorkflowNodeExecutionMetadataKey.AGENT_LOG: agent_logs, }, inputs=parameters_for_log, ) diff --git a/api/core/workflow/workflow_cycle_manager.py b/api/core/workflow/workflow_cycle_manager.py index 6e3c2f3f78..a6a5a04cc7 100644 --- a/api/core/workflow/workflow_cycle_manager.py +++ b/api/core/workflow/workflow_cycle_manager.py @@ -20,7 +20,7 @@ from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType from core.workflow.entities.workflow_node_execution import ( NodeExecution, - NodeRunMetadataKey, + WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) from core.workflow.enums import SystemVariableKey @@ -210,15 +210,15 @@ class WorkflowCycleManager: # Create a domain model created_at = datetime.now(UTC).replace(tzinfo=None) metadata = { - NodeRunMetadataKey.PARALLEL_MODE_RUN_ID: event.parallel_mode_run_id, - NodeRunMetadataKey.ITERATION_ID: event.in_iteration_id, - NodeRunMetadataKey.LOOP_ID: event.in_loop_id, + WorkflowNodeExecutionMetadataKey.PARALLEL_MODE_RUN_ID: event.parallel_mode_run_id, + WorkflowNodeExecutionMetadataKey.ITERATION_ID: event.in_iteration_id, + WorkflowNodeExecutionMetadataKey.LOOP_ID: event.in_loop_id, } domain_execution = NodeExecution( id=str(uuid4()), workflow_id=workflow_execution.workflow_id, - workflow_run_id=workflow_execution.id_, + workflow_execution_id=workflow_execution.id_, predecessor_node_id=event.predecessor_node_id, index=event.node_run_index, node_execution_id=event.node_execution_id, @@ -330,13 +330,13 @@ class WorkflowCycleManager: # Convert metadata keys to strings origin_metadata = { - NodeRunMetadataKey.ITERATION_ID: event.in_iteration_id, - NodeRunMetadataKey.PARALLEL_MODE_RUN_ID: event.parallel_mode_run_id, - NodeRunMetadataKey.LOOP_ID: event.in_loop_id, + WorkflowNodeExecutionMetadataKey.ITERATION_ID: event.in_iteration_id, + WorkflowNodeExecutionMetadataKey.PARALLEL_MODE_RUN_ID: event.parallel_mode_run_id, + WorkflowNodeExecutionMetadataKey.LOOP_ID: event.in_loop_id, } # Convert execution metadata keys to strings - execution_metadata_dict: dict[NodeRunMetadataKey, str | None] = {} + execution_metadata_dict: dict[WorkflowNodeExecutionMetadataKey, str | None] = {} if event.execution_metadata: for key, value in event.execution_metadata.items(): execution_metadata_dict[key] = value @@ -347,7 +347,7 @@ class WorkflowCycleManager: domain_execution = NodeExecution( id=str(uuid4()), workflow_id=workflow_execution.workflow_id, - workflow_run_id=workflow_execution.id_, + workflow_execution_id=workflow_execution.id_, predecessor_node_id=event.predecessor_node_id, node_execution_id=event.node_execution_id, node_id=event.node_id, diff --git a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py index 34c64121af..7535ec4866 100644 --- a/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py +++ b/api/tests/unit_tests/core/workflow/graph_engine/test_graph_engine.py @@ -4,7 +4,7 @@ import pytest from flask import Flask from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.node_entities import NodeRunResult, WorkflowNodeExecutionMetadataKey from core.workflow.entities.variable_pool import VariablePool from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey @@ -202,9 +202,9 @@ def test_run_parallel_in_workflow(mock_close, mock_remove): process_data={}, outputs={}, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: 1, - NodeRunMetadataKey.TOTAL_PRICE: 1, - NodeRunMetadataKey.CURRENCY: "USD", + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: 1, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: 1, + WorkflowNodeExecutionMetadataKey.CURRENCY: "USD", }, ) ) @@ -837,9 +837,9 @@ def test_condition_parallel_correct_output(mock_close, mock_remove, app): process_data={}, outputs={"class_name": "financial", "class_id": "1"}, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: 1, - NodeRunMetadataKey.TOTAL_PRICE: 1, - NodeRunMetadataKey.CURRENCY: "USD", + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: 1, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: 1, + WorkflowNodeExecutionMetadataKey.CURRENCY: "USD", }, edge_source_handle="1", ) @@ -853,9 +853,9 @@ def test_condition_parallel_correct_output(mock_close, mock_remove, app): process_data={}, outputs={"result": "dify 123"}, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: 1, - NodeRunMetadataKey.TOTAL_PRICE: 1, - NodeRunMetadataKey.CURRENCY: "USD", + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: 1, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: 1, + WorkflowNodeExecutionMetadataKey.CURRENCY: "USD", }, ) ) diff --git a/api/tests/unit_tests/core/workflow/nodes/test_continue_on_error.py b/api/tests/unit_tests/core/workflow/nodes/test_continue_on_error.py index c429ac7dd3..ff60d5974b 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_continue_on_error.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_continue_on_error.py @@ -1,7 +1,7 @@ from unittest.mock import patch from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult +from core.workflow.entities.node_entities import NodeRunResult, WorkflowNodeExecutionMetadataKey from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus from core.workflow.enums import SystemVariableKey from core.workflow.graph_engine.entities.event import ( @@ -543,9 +543,9 @@ def test_stream_output_with_fail_branch_continue_on_error(): process_data={}, outputs={}, metadata={ - NodeRunMetadataKey.TOTAL_TOKENS: 1, - NodeRunMetadataKey.TOTAL_PRICE: 1, - NodeRunMetadataKey.CURRENCY: "USD", + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: 1, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: 1, + WorkflowNodeExecutionMetadataKey.CURRENCY: "USD", }, ) ) diff --git a/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py b/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py index a5574d309b..fc4a8f1844 100644 --- a/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py +++ b/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py @@ -15,7 +15,7 @@ from core.app.entities.queue_entities import ( from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType from core.workflow.entities.workflow_node_execution import ( NodeExecution, - NodeRunMetadataKey, + WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) from core.workflow.enums import SystemVariableKey @@ -318,7 +318,7 @@ def test_handle_node_execution_start(workflow_cycle_manager, mock_workflow_execu # Verify the result assert result.workflow_id == workflow_execution.workflow_id - assert result.workflow_run_id == workflow_execution.id_ + assert result.workflow_execution_id == workflow_execution.id_ assert result.node_execution_id == event.node_execution_id assert result.node_id == event.node_id assert result.node_type == event.node_type @@ -368,7 +368,7 @@ def test_handle_workflow_node_execution_success(workflow_cycle_manager): event.inputs = {"input": "test input"} event.process_data = {"process": "test process"} event.outputs = {"output": "test output"} - event.execution_metadata = {NodeRunMetadataKey.TOTAL_TOKENS: 100} + event.execution_metadata = {WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: 100} event.start_at = datetime.now(UTC).replace(tzinfo=None) # Create a real node execution @@ -377,7 +377,7 @@ def test_handle_workflow_node_execution_success(workflow_cycle_manager): id="test-node-execution-record-id", node_execution_id="test-node-execution-id", workflow_id="test-workflow-id", - workflow_run_id="test-workflow-run-id", + workflow_execution_id="test-workflow-run-id", index=1, node_id="test-node-id", node_type=NodeType.LLM, @@ -445,7 +445,7 @@ def test_handle_workflow_node_execution_failed(workflow_cycle_manager): event.inputs = {"input": "test input"} event.process_data = {"process": "test process"} event.outputs = {"output": "test output"} - event.execution_metadata = {NodeRunMetadataKey.TOTAL_TOKENS: 100} + event.execution_metadata = {WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: 100} event.start_at = datetime.now(UTC).replace(tzinfo=None) event.error = "Test error message" @@ -455,7 +455,7 @@ def test_handle_workflow_node_execution_failed(workflow_cycle_manager): id="test-node-execution-record-id", node_execution_id="test-node-execution-id", workflow_id="test-workflow-id", - workflow_run_id="test-workflow-run-id", + workflow_execution_id="test-workflow-run-id", index=1, node_id="test-node-id", node_type=NodeType.LLM, diff --git a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py index f3cdfd135b..93282d33b0 100644 --- a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py +++ b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py @@ -15,7 +15,7 @@ from core.model_runtime.utils.encoders import jsonable_encoder from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.workflow.entities.workflow_node_execution import ( NodeExecution, - NodeRunMetadataKey, + WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) from core.workflow.nodes.enums import NodeType @@ -291,7 +291,7 @@ def test_to_db_model(repository): id="test-id", workflow_id="test-workflow-id", node_execution_id="test-node-execution-id", - workflow_run_id="test-workflow-run-id", + workflow_execution_id="test-workflow-run-id", index=1, predecessor_node_id="test-predecessor-id", node_id="test-node-id", @@ -303,7 +303,10 @@ def test_to_db_model(repository): status=WorkflowNodeExecutionStatus.RUNNING, error=None, elapsed_time=1.5, - metadata={NodeRunMetadataKey.TOTAL_TOKENS: 100, NodeRunMetadataKey.TOTAL_PRICE: Decimal("0.0")}, + metadata={ + WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS: 100, + WorkflowNodeExecutionMetadataKey.TOTAL_PRICE: Decimal("0.0"), + }, created_at=datetime.now(), finished_at=None, ) @@ -318,7 +321,7 @@ def test_to_db_model(repository): assert db_model.app_id == repository._app_id assert db_model.workflow_id == domain_model.workflow_id assert db_model.triggered_from == repository._triggered_from - assert db_model.workflow_run_id == domain_model.workflow_run_id + assert db_model.workflow_run_id == domain_model.workflow_execution_id assert db_model.index == domain_model.index assert db_model.predecessor_node_id == domain_model.predecessor_node_id assert db_model.node_execution_id == domain_model.node_execution_id @@ -346,7 +349,7 @@ def test_to_domain_model(repository): inputs_dict = {"input_key": "input_value"} process_data_dict = {"process_key": "process_value"} outputs_dict = {"output_key": "output_value"} - metadata_dict = {str(NodeRunMetadataKey.TOTAL_TOKENS): 100} + metadata_dict = {str(WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS): 100} # Create a DB model using our custom subclass db_model = WorkflowNodeExecution() @@ -381,7 +384,7 @@ def test_to_domain_model(repository): assert isinstance(domain_model, NodeExecution) assert domain_model.id == db_model.id assert domain_model.workflow_id == db_model.workflow_id - assert domain_model.workflow_run_id == db_model.workflow_run_id + assert domain_model.workflow_execution_id == db_model.workflow_run_id assert domain_model.index == db_model.index assert domain_model.predecessor_node_id == db_model.predecessor_node_id assert domain_model.node_execution_id == db_model.node_execution_id From f7fb10635f144d0774c708026152cd560921e504 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 04:56:37 +0800 Subject: [PATCH 04/73] refactor(workflow): Rename workflow node execution models (#20458) Signed-off-by: -LAN- --- .../common/workflow_response_converter.py | 8 +-- ...hemy_workflow_node_execution_repository.py | 60 +++++++++---------- .../entities/workflow_node_execution.py | 2 +- .../workflow_node_execution_repository.py | 10 ++-- api/core/workflow/workflow_cycle_manager.py | 14 ++--- api/models/__init__.py | 4 +- api/models/workflow.py | 2 +- .../clear_free_plan_tenant_expired_logs.py | 13 ++-- api/services/workflow_run_service.py | 4 +- api/services/workflow_service.py | 12 ++-- api/tasks/remove_app_and_related_data_task.py | 8 +-- .../workflow/test_workflow_cycle_manager.py | 6 +- api/tests/unit_tests/models/test_workflow.py | 4 +- .../test_sqlalchemy_repository.py | 28 ++++----- 14 files changed, 88 insertions(+), 87 deletions(-) diff --git a/api/core/app/apps/common/workflow_response_converter.py b/api/core/app/apps/common/workflow_response_converter.py index 8f8e429f0c..6f524a5872 100644 --- a/api/core/app/apps/common/workflow_response_converter.py +++ b/api/core/app/apps/common/workflow_response_converter.py @@ -45,7 +45,7 @@ from core.app.entities.task_entities import ( from core.file import FILE_MODEL_IDENTITY, File from core.tools.tool_manager import ToolManager from core.workflow.entities.workflow_execution import WorkflowExecution -from core.workflow.entities.workflow_node_execution import NodeExecution, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecution, WorkflowNodeExecutionStatus from core.workflow.nodes import NodeType from core.workflow.nodes.tool.entities import ToolNodeData from models import ( @@ -143,7 +143,7 @@ class WorkflowResponseConverter: *, event: QueueNodeStartedEvent, task_id: str, - workflow_node_execution: NodeExecution, + workflow_node_execution: WorkflowNodeExecution, ) -> Optional[NodeStartStreamResponse]: if workflow_node_execution.node_type in {NodeType.ITERATION, NodeType.LOOP}: return None @@ -193,7 +193,7 @@ class WorkflowResponseConverter: | QueueNodeInLoopFailedEvent | QueueNodeExceptionEvent, task_id: str, - workflow_node_execution: NodeExecution, + workflow_node_execution: WorkflowNodeExecution, ) -> Optional[NodeFinishStreamResponse]: if workflow_node_execution.node_type in {NodeType.ITERATION, NodeType.LOOP}: return None @@ -236,7 +236,7 @@ class WorkflowResponseConverter: *, event: QueueNodeRetryEvent, task_id: str, - workflow_node_execution: NodeExecution, + workflow_node_execution: WorkflowNodeExecution, ) -> Optional[Union[NodeRetryStreamResponse, NodeFinishStreamResponse]]: if workflow_node_execution.node_type in {NodeType.ITERATION, NodeType.LOOP}: return None diff --git a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py index e8a84d58ad..2f27442616 100644 --- a/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py +++ b/api/core/repositories/sqlalchemy_workflow_node_execution_repository.py @@ -13,7 +13,7 @@ from sqlalchemy.orm import sessionmaker from core.model_runtime.utils.encoders import jsonable_encoder from core.workflow.entities.workflow_node_execution import ( - NodeExecution, + WorkflowNodeExecution, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) @@ -23,7 +23,7 @@ from models import ( Account, CreatorUserRole, EndUser, - WorkflowNodeExecution, + WorkflowNodeExecutionModel, WorkflowNodeExecutionTriggeredFrom, ) @@ -86,9 +86,9 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) # Initialize in-memory cache for node executions # Key: node_execution_id, Value: WorkflowNodeExecution (DB model) - self._node_execution_cache: dict[str, WorkflowNodeExecution] = {} + self._node_execution_cache: dict[str, WorkflowNodeExecutionModel] = {} - def _to_domain_model(self, db_model: WorkflowNodeExecution) -> NodeExecution: + def _to_domain_model(self, db_model: WorkflowNodeExecutionModel) -> WorkflowNodeExecution: """ Convert a database model to a domain model. @@ -107,7 +107,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) # Convert status to domain enum status = WorkflowNodeExecutionStatus(db_model.status) - return NodeExecution( + return WorkflowNodeExecution( id=db_model.id, node_execution_id=db_model.node_execution_id, workflow_id=db_model.workflow_id, @@ -128,7 +128,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) finished_at=db_model.finished_at, ) - def to_db_model(self, domain_model: NodeExecution) -> WorkflowNodeExecution: + def to_db_model(self, domain_model: WorkflowNodeExecution) -> WorkflowNodeExecutionModel: """ Convert a domain model to a database model. @@ -146,7 +146,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) if not self._creator_user_role: raise ValueError("created_by_role is required in repository constructor") - db_model = WorkflowNodeExecution() + db_model = WorkflowNodeExecutionModel() db_model.id = domain_model.id db_model.tenant_id = self._tenant_id if self._app_id is not None: @@ -175,7 +175,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) db_model.finished_at = domain_model.finished_at return db_model - def save(self, execution: NodeExecution) -> None: + def save(self, execution: WorkflowNodeExecution) -> None: """ Save or update a NodeExecution domain entity to the database. @@ -207,7 +207,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) logger.debug(f"Updating cache for node_execution_id: {db_model.node_execution_id}") self._node_execution_cache[db_model.node_execution_id] = db_model - def get_by_node_execution_id(self, node_execution_id: str) -> Optional[NodeExecution]: + def get_by_node_execution_id(self, node_execution_id: str) -> Optional[WorkflowNodeExecution]: """ Retrieve a NodeExecution by its node_execution_id. @@ -230,13 +230,13 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) # If not in cache, query the database logger.debug(f"Cache miss for node_execution_id: {node_execution_id}, querying database") with self._session_factory() as session: - stmt = select(WorkflowNodeExecution).where( - WorkflowNodeExecution.node_execution_id == node_execution_id, - WorkflowNodeExecution.tenant_id == self._tenant_id, + stmt = select(WorkflowNodeExecutionModel).where( + WorkflowNodeExecutionModel.node_execution_id == node_execution_id, + WorkflowNodeExecutionModel.tenant_id == self._tenant_id, ) if self._app_id: - stmt = stmt.where(WorkflowNodeExecution.app_id == self._app_id) + stmt = stmt.where(WorkflowNodeExecutionModel.app_id == self._app_id) db_model = session.scalar(stmt) if db_model: @@ -252,7 +252,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) self, workflow_run_id: str, order_config: Optional[OrderConfig] = None, - ) -> Sequence[WorkflowNodeExecution]: + ) -> Sequence[WorkflowNodeExecutionModel]: """ Retrieve all WorkflowNodeExecution database models for a specific workflow run. @@ -270,20 +270,20 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) A list of WorkflowNodeExecution database models """ with self._session_factory() as session: - stmt = select(WorkflowNodeExecution).where( - WorkflowNodeExecution.workflow_run_id == workflow_run_id, - WorkflowNodeExecution.tenant_id == self._tenant_id, - WorkflowNodeExecution.triggered_from == WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN, + stmt = select(WorkflowNodeExecutionModel).where( + WorkflowNodeExecutionModel.workflow_run_id == workflow_run_id, + WorkflowNodeExecutionModel.tenant_id == self._tenant_id, + WorkflowNodeExecutionModel.triggered_from == WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN, ) if self._app_id: - stmt = stmt.where(WorkflowNodeExecution.app_id == self._app_id) + stmt = stmt.where(WorkflowNodeExecutionModel.app_id == self._app_id) # Apply ordering if provided if order_config and order_config.order_by: order_columns: list[UnaryExpression] = [] for field in order_config.order_by: - column = getattr(WorkflowNodeExecution, field, None) + column = getattr(WorkflowNodeExecutionModel, field, None) if not column: continue if order_config.order_direction == "desc": @@ -307,7 +307,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) self, workflow_run_id: str, order_config: Optional[OrderConfig] = None, - ) -> Sequence[NodeExecution]: + ) -> Sequence[WorkflowNodeExecution]: """ Retrieve all NodeExecution instances for a specific workflow run. @@ -334,7 +334,7 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) return domain_models - def get_running_executions(self, workflow_run_id: str) -> Sequence[NodeExecution]: + def get_running_executions(self, workflow_run_id: str) -> Sequence[WorkflowNodeExecution]: """ Retrieve all running NodeExecution instances for a specific workflow run. @@ -348,15 +348,15 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) A list of running NodeExecution instances """ with self._session_factory() as session: - stmt = select(WorkflowNodeExecution).where( - WorkflowNodeExecution.workflow_run_id == workflow_run_id, - WorkflowNodeExecution.tenant_id == self._tenant_id, - WorkflowNodeExecution.status == WorkflowNodeExecutionStatus.RUNNING, - WorkflowNodeExecution.triggered_from == WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN, + stmt = select(WorkflowNodeExecutionModel).where( + WorkflowNodeExecutionModel.workflow_run_id == workflow_run_id, + WorkflowNodeExecutionModel.tenant_id == self._tenant_id, + WorkflowNodeExecutionModel.status == WorkflowNodeExecutionStatus.RUNNING, + WorkflowNodeExecutionModel.triggered_from == WorkflowNodeExecutionTriggeredFrom.WORKFLOW_RUN, ) if self._app_id: - stmt = stmt.where(WorkflowNodeExecution.app_id == self._app_id) + stmt = stmt.where(WorkflowNodeExecutionModel.app_id == self._app_id) db_models = session.scalars(stmt).all() domain_models = [] @@ -381,10 +381,10 @@ class SQLAlchemyWorkflowNodeExecutionRepository(WorkflowNodeExecutionRepository) It also clears the in-memory cache. """ with self._session_factory() as session: - stmt = delete(WorkflowNodeExecution).where(WorkflowNodeExecution.tenant_id == self._tenant_id) + stmt = delete(WorkflowNodeExecutionModel).where(WorkflowNodeExecutionModel.tenant_id == self._tenant_id) if self._app_id: - stmt = stmt.where(WorkflowNodeExecution.app_id == self._app_id) + stmt = stmt.where(WorkflowNodeExecutionModel.app_id == self._app_id) result = session.execute(stmt) session.commit() diff --git a/api/core/workflow/entities/workflow_node_execution.py b/api/core/workflow/entities/workflow_node_execution.py index 8e19fea43f..773f5b777b 100644 --- a/api/core/workflow/entities/workflow_node_execution.py +++ b/api/core/workflow/entities/workflow_node_execution.py @@ -53,7 +53,7 @@ class WorkflowNodeExecutionStatus(StrEnum): RETRY = "retry" -class NodeExecution(BaseModel): +class WorkflowNodeExecution(BaseModel): """ Domain model for workflow node execution. diff --git a/api/core/workflow/repositories/workflow_node_execution_repository.py b/api/core/workflow/repositories/workflow_node_execution_repository.py index 8c83b5ea6c..1908a6b190 100644 --- a/api/core/workflow/repositories/workflow_node_execution_repository.py +++ b/api/core/workflow/repositories/workflow_node_execution_repository.py @@ -2,7 +2,7 @@ from collections.abc import Sequence from dataclasses import dataclass from typing import Literal, Optional, Protocol -from core.workflow.entities.workflow_node_execution import NodeExecution +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecution @dataclass @@ -26,7 +26,7 @@ class WorkflowNodeExecutionRepository(Protocol): application domains or deployment scenarios. """ - def save(self, execution: NodeExecution) -> None: + def save(self, execution: WorkflowNodeExecution) -> None: """ Save or update a NodeExecution instance. @@ -39,7 +39,7 @@ class WorkflowNodeExecutionRepository(Protocol): """ ... - def get_by_node_execution_id(self, node_execution_id: str) -> Optional[NodeExecution]: + def get_by_node_execution_id(self, node_execution_id: str) -> Optional[WorkflowNodeExecution]: """ Retrieve a NodeExecution by its node_execution_id. @@ -55,7 +55,7 @@ class WorkflowNodeExecutionRepository(Protocol): self, workflow_run_id: str, order_config: Optional[OrderConfig] = None, - ) -> Sequence[NodeExecution]: + ) -> Sequence[WorkflowNodeExecution]: """ Retrieve all NodeExecution instances for a specific workflow run. @@ -70,7 +70,7 @@ class WorkflowNodeExecutionRepository(Protocol): """ ... - def get_running_executions(self, workflow_run_id: str) -> Sequence[NodeExecution]: + def get_running_executions(self, workflow_run_id: str) -> Sequence[WorkflowNodeExecution]: """ Retrieve all running NodeExecution instances for a specific workflow run. diff --git a/api/core/workflow/workflow_cycle_manager.py b/api/core/workflow/workflow_cycle_manager.py index a6a5a04cc7..6365ab53a2 100644 --- a/api/core/workflow/workflow_cycle_manager.py +++ b/api/core/workflow/workflow_cycle_manager.py @@ -19,7 +19,7 @@ from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType from core.workflow.entities.workflow_node_execution import ( - NodeExecution, + WorkflowNodeExecution, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) @@ -204,7 +204,7 @@ class WorkflowCycleManager: *, workflow_execution_id: str, event: QueueNodeStartedEvent, - ) -> NodeExecution: + ) -> WorkflowNodeExecution: workflow_execution = self._get_workflow_execution_or_raise_error(workflow_execution_id) # Create a domain model @@ -215,7 +215,7 @@ class WorkflowCycleManager: WorkflowNodeExecutionMetadataKey.LOOP_ID: event.in_loop_id, } - domain_execution = NodeExecution( + domain_execution = WorkflowNodeExecution( id=str(uuid4()), workflow_id=workflow_execution.workflow_id, workflow_execution_id=workflow_execution.id_, @@ -235,7 +235,7 @@ class WorkflowCycleManager: return domain_execution - def handle_workflow_node_execution_success(self, *, event: QueueNodeSucceededEvent) -> NodeExecution: + def handle_workflow_node_execution_success(self, *, event: QueueNodeSucceededEvent) -> WorkflowNodeExecution: # Get the domain model from repository domain_execution = self._workflow_node_execution_repository.get_by_node_execution_id(event.node_execution_id) if not domain_execution: @@ -275,7 +275,7 @@ class WorkflowCycleManager: | QueueNodeInIterationFailedEvent | QueueNodeInLoopFailedEvent | QueueNodeExceptionEvent, - ) -> NodeExecution: + ) -> WorkflowNodeExecution: """ Workflow node execution failed :param event: queue node failed event @@ -320,7 +320,7 @@ class WorkflowCycleManager: def handle_workflow_node_execution_retried( self, *, workflow_execution_id: str, event: QueueNodeRetryEvent - ) -> NodeExecution: + ) -> WorkflowNodeExecution: workflow_execution = self._get_workflow_execution_or_raise_error(workflow_execution_id) created_at = event.start_at finished_at = datetime.now(UTC).replace(tzinfo=None) @@ -344,7 +344,7 @@ class WorkflowCycleManager: merged_metadata = {**execution_metadata_dict, **origin_metadata} if execution_metadata_dict else origin_metadata # Create a domain model - domain_execution = NodeExecution( + domain_execution = WorkflowNodeExecution( id=str(uuid4()), workflow_id=workflow_execution.workflow_id, workflow_execution_id=workflow_execution.id_, diff --git a/api/models/__init__.py b/api/models/__init__.py index 13eab226b7..83b50eb099 100644 --- a/api/models/__init__.py +++ b/api/models/__init__.py @@ -84,7 +84,7 @@ from .workflow import ( Workflow, WorkflowAppLog, WorkflowAppLogCreatedFrom, - WorkflowNodeExecution, + WorkflowNodeExecutionModel, WorkflowNodeExecutionTriggeredFrom, WorkflowRun, WorkflowType, @@ -169,7 +169,7 @@ __all__ = [ "Workflow", "WorkflowAppLog", "WorkflowAppLogCreatedFrom", - "WorkflowNodeExecution", + "WorkflowNodeExecutionModel", "WorkflowNodeExecutionTriggeredFrom", "WorkflowRun", "WorkflowRunTriggeredFrom", diff --git a/api/models/workflow.py b/api/models/workflow.py index 6a162d52d4..a92faf390f 100644 --- a/api/models/workflow.py +++ b/api/models/workflow.py @@ -541,7 +541,7 @@ class WorkflowNodeExecutionTriggeredFrom(StrEnum): WORKFLOW_RUN = "workflow-run" -class WorkflowNodeExecution(Base): +class WorkflowNodeExecutionModel(Base): """ Workflow Node Execution diff --git a/api/services/clear_free_plan_tenant_expired_logs.py b/api/services/clear_free_plan_tenant_expired_logs.py index 5762bf9600..1fd560d581 100644 --- a/api/services/clear_free_plan_tenant_expired_logs.py +++ b/api/services/clear_free_plan_tenant_expired_logs.py @@ -14,7 +14,7 @@ from extensions.ext_database import db from extensions.ext_storage import storage from models.account import Tenant from models.model import App, Conversation, Message -from models.workflow import WorkflowNodeExecution, WorkflowRun +from models.workflow import WorkflowNodeExecutionModel, WorkflowRun from services.billing_service import BillingService logger = logging.getLogger(__name__) @@ -108,10 +108,11 @@ class ClearFreePlanTenantExpiredLogs: while True: with Session(db.engine).no_autoflush as session: workflow_node_executions = ( - session.query(WorkflowNodeExecution) + session.query(WorkflowNodeExecutionModel) .filter( - WorkflowNodeExecution.tenant_id == tenant_id, - WorkflowNodeExecution.created_at < datetime.datetime.now() - datetime.timedelta(days=days), + WorkflowNodeExecutionModel.tenant_id == tenant_id, + WorkflowNodeExecutionModel.created_at + < datetime.datetime.now() - datetime.timedelta(days=days), ) .limit(batch) .all() @@ -135,8 +136,8 @@ class ClearFreePlanTenantExpiredLogs: ] # delete workflow node executions - session.query(WorkflowNodeExecution).filter( - WorkflowNodeExecution.id.in_(workflow_node_execution_ids), + session.query(WorkflowNodeExecutionModel).filter( + WorkflowNodeExecutionModel.id.in_(workflow_node_execution_ids), ).delete(synchronize_session=False) session.commit() diff --git a/api/services/workflow_run_service.py b/api/services/workflow_run_service.py index 0ad900d758..483c0d3086 100644 --- a/api/services/workflow_run_service.py +++ b/api/services/workflow_run_service.py @@ -11,7 +11,7 @@ from models import ( Account, App, EndUser, - WorkflowNodeExecution, + WorkflowNodeExecutionModel, WorkflowRun, WorkflowRunTriggeredFrom, ) @@ -125,7 +125,7 @@ class WorkflowRunService: app_model: App, run_id: str, user: Account | EndUser, - ) -> Sequence[WorkflowNodeExecution]: + ) -> Sequence[WorkflowNodeExecutionModel]: """ Get workflow run node execution list """ diff --git a/api/services/workflow_service.py b/api/services/workflow_service.py index 2460aa25a7..bc213ccce6 100644 --- a/api/services/workflow_service.py +++ b/api/services/workflow_service.py @@ -13,7 +13,7 @@ from core.app.apps.workflow.app_config_manager import WorkflowAppConfigManager from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.variables import Variable from core.workflow.entities.node_entities import NodeRunResult -from core.workflow.entities.workflow_node_execution import NodeExecution, WorkflowNodeExecutionStatus +from core.workflow.entities.workflow_node_execution import WorkflowNodeExecution, WorkflowNodeExecutionStatus from core.workflow.errors import WorkflowNodeRunFailedError from core.workflow.graph_engine.entities.event import InNodeEvent from core.workflow.nodes import NodeType @@ -30,7 +30,7 @@ from models.model import App, AppMode from models.tools import WorkflowToolProvider from models.workflow import ( Workflow, - WorkflowNodeExecution, + WorkflowNodeExecutionModel, WorkflowNodeExecutionTriggeredFrom, WorkflowType, ) @@ -254,7 +254,7 @@ class WorkflowService: def run_draft_workflow_node( self, app_model: App, node_id: str, user_inputs: dict, account: Account - ) -> WorkflowNodeExecution: + ) -> WorkflowNodeExecutionModel: """ Run draft workflow node """ @@ -296,7 +296,7 @@ class WorkflowService: def run_free_workflow_node( self, node_data: dict, tenant_id: str, user_id: str, node_id: str, user_inputs: dict[str, Any] - ) -> NodeExecution: + ) -> WorkflowNodeExecution: """ Run draft workflow node """ @@ -322,7 +322,7 @@ class WorkflowService: invoke_node_fn: Callable[[], tuple[BaseNode, Generator[NodeEvent | InNodeEvent, None, None]]], start_at: float, node_id: str, - ) -> NodeExecution: + ) -> WorkflowNodeExecution: try: node_instance, generator = invoke_node_fn() @@ -374,7 +374,7 @@ class WorkflowService: error = e.error # Create a NodeExecution domain model - node_execution = NodeExecution( + node_execution = WorkflowNodeExecution( id=str(uuid4()), workflow_id="", # This is a single-step execution, so no workflow ID index=1, diff --git a/api/tasks/remove_app_and_related_data_task.py b/api/tasks/remove_app_and_related_data_task.py index 4e527bbaed..d366efd6f2 100644 --- a/api/tasks/remove_app_and_related_data_task.py +++ b/api/tasks/remove_app_and_related_data_task.py @@ -30,7 +30,7 @@ from models import ( ) from models.tools import WorkflowToolProvider from models.web import PinnedConversation, SavedMessage -from models.workflow import ConversationVariable, Workflow, WorkflowAppLog, WorkflowNodeExecution, WorkflowRun +from models.workflow import ConversationVariable, Workflow, WorkflowAppLog, WorkflowNodeExecutionModel, WorkflowRun @shared_task(queue="app_deletion", bind=True, max_retries=3) @@ -188,9 +188,9 @@ def _delete_app_workflow_runs(tenant_id: str, app_id: str): def _delete_app_workflow_node_executions(tenant_id: str, app_id: str): def del_workflow_node_execution(workflow_node_execution_id: str): - db.session.query(WorkflowNodeExecution).filter(WorkflowNodeExecution.id == workflow_node_execution_id).delete( - synchronize_session=False - ) + db.session.query(WorkflowNodeExecutionModel).filter( + WorkflowNodeExecutionModel.id == workflow_node_execution_id + ).delete(synchronize_session=False) _delete_records( """select id from workflow_node_executions where tenant_id=:tenant_id and app_id=:app_id limit 1000""", diff --git a/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py b/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py index fc4a8f1844..db75370d67 100644 --- a/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py +++ b/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py @@ -14,7 +14,7 @@ from core.app.entities.queue_entities import ( ) from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType from core.workflow.entities.workflow_node_execution import ( - NodeExecution, + WorkflowNodeExecution, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) @@ -373,7 +373,7 @@ def test_handle_workflow_node_execution_success(workflow_cycle_manager): # Create a real node execution - node_execution = NodeExecution( + node_execution = WorkflowNodeExecution( id="test-node-execution-record-id", node_execution_id="test-node-execution-id", workflow_id="test-workflow-id", @@ -451,7 +451,7 @@ def test_handle_workflow_node_execution_failed(workflow_cycle_manager): # Create a real node execution - node_execution = NodeExecution( + node_execution = WorkflowNodeExecution( id="test-node-execution-record-id", node_execution_id="test-node-execution-id", workflow_id="test-workflow-id", diff --git a/api/tests/unit_tests/models/test_workflow.py b/api/tests/unit_tests/models/test_workflow.py index 34802d47a7..b79e95c7ed 100644 --- a/api/tests/unit_tests/models/test_workflow.py +++ b/api/tests/unit_tests/models/test_workflow.py @@ -4,7 +4,7 @@ from uuid import uuid4 from constants import HIDDEN_VALUE from core.variables import FloatVariable, IntegerVariable, SecretVariable, StringVariable -from models.workflow import Workflow, WorkflowNodeExecution +from models.workflow import Workflow, WorkflowNodeExecutionModel def test_environment_variables(): @@ -156,7 +156,7 @@ def test_to_dict(): class TestWorkflowNodeExecution: def test_execution_metadata_dict(self): - node_exec = WorkflowNodeExecution() + node_exec = WorkflowNodeExecutionModel() node_exec.execution_metadata = None assert node_exec.execution_metadata_dict == {} diff --git a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py index 93282d33b0..643efb0a0c 100644 --- a/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py +++ b/api/tests/unit_tests/repositories/workflow_node_execution/test_sqlalchemy_repository.py @@ -14,14 +14,14 @@ from sqlalchemy.orm import Session, sessionmaker from core.model_runtime.utils.encoders import jsonable_encoder from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.workflow.entities.workflow_node_execution import ( - NodeExecution, + WorkflowNodeExecution, WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus, ) from core.workflow.nodes.enums import NodeType from core.workflow.repositories.workflow_node_execution_repository import OrderConfig from models.account import Account, Tenant -from models.workflow import WorkflowNodeExecution, WorkflowNodeExecutionTriggeredFrom +from models.workflow import WorkflowNodeExecutionModel, WorkflowNodeExecutionTriggeredFrom def configure_mock_execution(mock_execution): @@ -85,7 +85,7 @@ def test_save(repository, session): """Test save method.""" session_obj, _ = session # Create a mock execution - execution = MagicMock(spec=WorkflowNodeExecution) + execution = MagicMock(spec=WorkflowNodeExecutionModel) execution.tenant_id = None execution.app_id = None execution.inputs = None @@ -111,7 +111,7 @@ def test_save_with_existing_tenant_id(repository, session): """Test save method with existing tenant_id.""" session_obj, _ = session # Create a mock execution with existing tenant_id - execution = MagicMock(spec=WorkflowNodeExecution) + execution = MagicMock(spec=WorkflowNodeExecutionModel) execution.tenant_id = "existing-tenant" execution.app_id = None execution.inputs = None @@ -120,7 +120,7 @@ def test_save_with_existing_tenant_id(repository, session): execution.metadata = None # Create a modified execution that will be returned by _to_db_model - modified_execution = MagicMock(spec=WorkflowNodeExecution) + modified_execution = MagicMock(spec=WorkflowNodeExecutionModel) modified_execution.tenant_id = "existing-tenant" # Tenant ID should not change modified_execution.app_id = repository._app_id # App ID should be set @@ -147,7 +147,7 @@ def test_get_by_node_execution_id(repository, session, mocker: MockerFixture): mock_stmt.where.return_value = mock_stmt # Create a properly configured mock execution - mock_execution = mocker.MagicMock(spec=WorkflowNodeExecution) + mock_execution = mocker.MagicMock(spec=WorkflowNodeExecutionModel) configure_mock_execution(mock_execution) session_obj.scalar.return_value = mock_execution @@ -179,7 +179,7 @@ def test_get_by_workflow_run(repository, session, mocker: MockerFixture): mock_stmt.order_by.return_value = mock_stmt # Create a properly configured mock execution - mock_execution = mocker.MagicMock(spec=WorkflowNodeExecution) + mock_execution = mocker.MagicMock(spec=WorkflowNodeExecutionModel) configure_mock_execution(mock_execution) session_obj.scalars.return_value.all.return_value = [mock_execution] @@ -212,7 +212,7 @@ def test_get_running_executions(repository, session, mocker: MockerFixture): mock_stmt.where.return_value = mock_stmt # Create a properly configured mock execution - mock_execution = mocker.MagicMock(spec=WorkflowNodeExecution) + mock_execution = mocker.MagicMock(spec=WorkflowNodeExecutionModel) configure_mock_execution(mock_execution) session_obj.scalars.return_value.all.return_value = [mock_execution] @@ -238,7 +238,7 @@ def test_update_via_save(repository, session): """Test updating an existing record via save method.""" session_obj, _ = session # Create a mock execution - execution = MagicMock(spec=WorkflowNodeExecution) + execution = MagicMock(spec=WorkflowNodeExecutionModel) execution.tenant_id = None execution.app_id = None execution.inputs = None @@ -278,7 +278,7 @@ def test_clear(repository, session, mocker: MockerFixture): repository.clear() # Assert delete was called with correct parameters - mock_delete.assert_called_once_with(WorkflowNodeExecution) + mock_delete.assert_called_once_with(WorkflowNodeExecutionModel) mock_stmt.where.assert_called() session_obj.execute.assert_called_once_with(mock_stmt) session_obj.commit.assert_called_once() @@ -287,7 +287,7 @@ def test_clear(repository, session, mocker: MockerFixture): def test_to_db_model(repository): """Test to_db_model method.""" # Create a domain model - domain_model = NodeExecution( + domain_model = WorkflowNodeExecution( id="test-id", workflow_id="test-workflow-id", node_execution_id="test-node-execution-id", @@ -315,7 +315,7 @@ def test_to_db_model(repository): db_model = repository.to_db_model(domain_model) # Assert DB model has correct values - assert isinstance(db_model, WorkflowNodeExecution) + assert isinstance(db_model, WorkflowNodeExecutionModel) assert db_model.id == domain_model.id assert db_model.tenant_id == repository._tenant_id assert db_model.app_id == repository._app_id @@ -352,7 +352,7 @@ def test_to_domain_model(repository): metadata_dict = {str(WorkflowNodeExecutionMetadataKey.TOTAL_TOKENS): 100} # Create a DB model using our custom subclass - db_model = WorkflowNodeExecution() + db_model = WorkflowNodeExecutionModel() db_model.id = "test-id" db_model.tenant_id = "test-tenant-id" db_model.app_id = "test-app-id" @@ -381,7 +381,7 @@ def test_to_domain_model(repository): domain_model = repository._to_domain_model(db_model) # Assert domain model has correct values - assert isinstance(domain_model, NodeExecution) + assert isinstance(domain_model, WorkflowNodeExecution) assert domain_model.id == db_model.id assert domain_model.workflow_id == db_model.workflow_id assert domain_model.workflow_execution_id == db_model.workflow_run_id From 2ebf4e767bc5844ed3f1e5fc53edaefd167dfe10 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 07:53:13 +0800 Subject: [PATCH 05/73] fix(models): WorkflowRun's total_steps and exceptions_count mismatch with database (#20452) Signed-off-by: -LAN- --- api/models/workflow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/models/workflow.py b/api/models/workflow.py index a92faf390f..e868fb77a7 100644 --- a/api/models/workflow.py +++ b/api/models/workflow.py @@ -437,12 +437,12 @@ class WorkflowRun(Base): error: Mapped[Optional[str]] = mapped_column(db.Text) elapsed_time: Mapped[float] = mapped_column(db.Float, nullable=False, server_default=sa.text("0")) total_tokens: Mapped[int] = mapped_column(sa.BigInteger, server_default=sa.text("0")) - total_steps: Mapped[int] = mapped_column(db.Integer, server_default=db.text("0")) + total_steps: Mapped[int] = mapped_column(db.Integer, server_default=db.text("0"), nullable=True) created_by_role: Mapped[str] = mapped_column(db.String(255)) # account, end_user created_by: Mapped[str] = mapped_column(StringUUID, nullable=False) created_at: Mapped[datetime] = mapped_column(db.DateTime, nullable=False, server_default=func.current_timestamp()) finished_at: Mapped[Optional[datetime]] = mapped_column(db.DateTime) - exceptions_count: Mapped[int] = mapped_column(db.Integer, server_default=db.text("0")) + exceptions_count: Mapped[int] = mapped_column(db.Integer, server_default=db.text("0"), nullable=True) @property def created_by_account(self): From f2e0d161a19e4a7bb58f62800cbcad8c3423e038 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 09:00:05 +0800 Subject: [PATCH 06/73] fix(ops_trace_manager): Adds app_id to TraceTask initialization (#20461) Signed-off-by: -LAN- --- api/core/ops/langfuse_trace/langfuse_trace.py | 7 +++++++ api/core/ops/ops_trace_manager.py | 1 + 2 files changed, 8 insertions(+) diff --git a/api/core/ops/langfuse_trace/langfuse_trace.py b/api/core/ops/langfuse_trace/langfuse_trace.py index 120c36f53d..fa1c6b4557 100644 --- a/api/core/ops/langfuse_trace/langfuse_trace.py +++ b/api/core/ops/langfuse_trace/langfuse_trace.py @@ -32,6 +32,7 @@ from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.workflow.nodes.enums import NodeType from extensions.ext_database import db from models import Account, App, EndUser, WorkflowNodeExecutionTriggeredFrom +from models.account import TenantAccountJoin logger = logging.getLogger(__name__) @@ -130,6 +131,12 @@ class LangFuseDataTrace(BaseTraceInstance): service_account = session.query(Account).filter(Account.id == app.created_by).first() if not service_account: raise ValueError(f"Creator account with id {app.created_by} not found for app {app_id}") + current_tenant = ( + session.query(TenantAccountJoin).filter_by(account_id=service_account.id, current=True).first() + ) + if not current_tenant: + raise ValueError(f"Current tenant not found for account {service_account.id}") + service_account.set_tenant_id(current_tenant.tenant_id) workflow_node_execution_repository = SQLAlchemyWorkflowNodeExecutionRepository( session_factory=session_factory, diff --git a/api/core/ops/ops_trace_manager.py b/api/core/ops/ops_trace_manager.py index addf164e6f..dc4cfc48db 100644 --- a/api/core/ops/ops_trace_manager.py +++ b/api/core/ops/ops_trace_manager.py @@ -487,6 +487,7 @@ class TraceTask: "file_list": file_list, "triggered_from": workflow_run.triggered_from, "user_id": user_id, + "app_id": workflow_run.app_id, } workflow_trace_info = WorkflowTraceInfo( From 91eeb2ab76bd9992b76035939e94924602c089dc Mon Sep 17 00:00:00 2001 From: Davide Delbianco Date: Fri, 30 May 2025 03:24:31 +0200 Subject: [PATCH 07/73] chore: Colorize new OpenAI LLM versions (#20463) Co-authored-by: Davide Delbianco --- .../base/icons/src/public/llm/OpenaiTale.json | 37 +++++++++++++++++++ .../base/icons/src/public/llm/OpenaiTale.tsx | 20 ++++++++++ .../icons/src/public/llm/OpenaiYellow.json | 37 +++++++++++++++++++ .../icons/src/public/llm/OpenaiYellow.tsx | 20 ++++++++++ .../base/icons/src/public/llm/index.ts | 2 + .../model-provider-page/model-icon/index.tsx | 6 ++- 6 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 web/app/components/base/icons/src/public/llm/OpenaiTale.json create mode 100644 web/app/components/base/icons/src/public/llm/OpenaiTale.tsx create mode 100644 web/app/components/base/icons/src/public/llm/OpenaiYellow.json create mode 100644 web/app/components/base/icons/src/public/llm/OpenaiYellow.tsx diff --git a/web/app/components/base/icons/src/public/llm/OpenaiTale.json b/web/app/components/base/icons/src/public/llm/OpenaiTale.json new file mode 100644 index 0000000000..45943139f1 --- /dev/null +++ b/web/app/components/base/icons/src/public/llm/OpenaiTale.json @@ -0,0 +1,37 @@ +{ + "icon": { + "type": "element", + "isRootNode": true, + "name": "svg", + "attributes": { + "width": "24", + "height": "24", + "viewBox": "0 0 24 24", + "fill": "none", + "xmlns": "http://www.w3.org/2000/svg" + }, + "children": [ + { + "type": "element", + "name": "rect", + "attributes": { + "width": "24", + "height": "24", + "rx": "6", + "fill": "#009688" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z", + "fill": "white" + }, + "children": [] + } + ] + }, + "name": "OpenaiTale" +} diff --git a/web/app/components/base/icons/src/public/llm/OpenaiTale.tsx b/web/app/components/base/icons/src/public/llm/OpenaiTale.tsx new file mode 100644 index 0000000000..e7ae45e293 --- /dev/null +++ b/web/app/components/base/icons/src/public/llm/OpenaiTale.tsx @@ -0,0 +1,20 @@ +// GENERATE BY script +// DON NOT EDIT IT MANUALLY + +import * as React from 'react' +import data from './OpenaiTale.json' +import IconBase from '@/app/components/base/icons/IconBase' +import type { IconData } from '@/app/components/base/icons/IconBase' + +const Icon = ( + { + ref, + ...props + }: React.SVGProps & { + ref?: React.RefObject>; + }, +) => + +Icon.displayName = 'OpenaiTale' + +export default Icon diff --git a/web/app/components/base/icons/src/public/llm/OpenaiYellow.json b/web/app/components/base/icons/src/public/llm/OpenaiYellow.json new file mode 100644 index 0000000000..d0a4f10744 --- /dev/null +++ b/web/app/components/base/icons/src/public/llm/OpenaiYellow.json @@ -0,0 +1,37 @@ +{ + "icon": { + "type": "element", + "isRootNode": true, + "name": "svg", + "attributes": { + "width": "24", + "height": "24", + "viewBox": "0 0 24 24", + "fill": "none", + "xmlns": "http://www.w3.org/2000/svg" + }, + "children": [ + { + "type": "element", + "name": "rect", + "attributes": { + "width": "24", + "height": "24", + "rx": "6", + "fill": "#FAB005" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z", + "fill": "white" + }, + "children": [] + } + ] + }, + "name": "OpenaiYellow" +} diff --git a/web/app/components/base/icons/src/public/llm/OpenaiYellow.tsx b/web/app/components/base/icons/src/public/llm/OpenaiYellow.tsx new file mode 100644 index 0000000000..77dac7e322 --- /dev/null +++ b/web/app/components/base/icons/src/public/llm/OpenaiYellow.tsx @@ -0,0 +1,20 @@ +// GENERATE BY script +// DON NOT EDIT IT MANUALLY + +import * as React from 'react' +import data from './OpenaiYellow.json' +import IconBase from '@/app/components/base/icons/IconBase' +import type { IconData } from '@/app/components/base/icons/IconBase' + +const Icon = ( + { + ref, + ...props + }: React.SVGProps & { + ref?: React.RefObject>; + }, +) => + +Icon.displayName = 'OpenaiYellow' + +export default Icon diff --git a/web/app/components/base/icons/src/public/llm/index.ts b/web/app/components/base/icons/src/public/llm/index.ts index cc9b531ebf..c20f72d8be 100644 --- a/web/app/components/base/icons/src/public/llm/index.ts +++ b/web/app/components/base/icons/src/public/llm/index.ts @@ -30,7 +30,9 @@ export { default as OpenaiBlue } from './OpenaiBlue' export { default as OpenaiGreen } from './OpenaiGreen' export { default as OpenaiText } from './OpenaiText' export { default as OpenaiTransparent } from './OpenaiTransparent' +export { default as OpenaiTale } from './OpenaiTale' export { default as OpenaiViolet } from './OpenaiViolet' +export { default as OpenaiYellow } from './OpenaiYellow' export { default as OpenllmText } from './OpenllmText' export { default as Openllm } from './Openllm' export { default as ReplicateText } from './ReplicateText' diff --git a/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx b/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx index d302defcfe..6f93e2871d 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx @@ -5,7 +5,7 @@ import type { } from '../declarations' import { useLanguage } from '../hooks' import { Group } from '@/app/components/base/icons/src/vender/other' -import { OpenaiBlue, OpenaiViolet } from '@/app/components/base/icons/src/public/llm' +import { OpenaiBlue, OpenaiTale, OpenaiViolet, OpenaiYellow } from '@/app/components/base/icons/src/public/llm' import cn from '@/utils/classnames' import { renderI18nObject } from '@/i18n' @@ -22,6 +22,10 @@ const ModelIcon: FC = ({ isDeprecated = false, }) => { const language = useLanguage() + if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.startsWith('o')) + return
+ if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.includes('gpt-4.1')) + return
if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.includes('gpt-4o')) return
if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.startsWith('gpt-4')) From 8e2d342de6f01ce41137739f1bdff5b12b2179cd Mon Sep 17 00:00:00 2001 From: crazywoola <100913391+crazywoola@users.noreply.github.com> Date: Fri, 30 May 2025 10:51:19 +0800 Subject: [PATCH 08/73] Feat/15534 support replacing the bot in chat input placeholder with the bots name (#20473) --- .../debug/debug-with-multiple-model/index.tsx | 11 ++++++++++- .../base/chat/chat/chat-input-area/index.tsx | 4 +++- web/app/components/base/chat/chat/index.tsx | 1 + web/i18n/de-DE/common.ts | 2 +- web/i18n/en-US/common.ts | 2 +- web/i18n/es-ES/common.ts | 2 +- web/i18n/fr-FR/common.ts | 2 +- web/i18n/it-IT/common.ts | 2 +- web/i18n/ja-JP/common.ts | 2 +- web/i18n/pl-PL/common.ts | 2 +- web/i18n/pt-BR/common.ts | 2 +- web/i18n/ro-RO/common.ts | 2 +- web/i18n/tr-TR/common.ts | 2 +- web/i18n/vi-VN/common.ts | 2 +- web/i18n/zh-Hans/common.ts | 2 +- web/i18n/zh-Hant/common.ts | 2 +- web/models/debug.ts | 1 + 17 files changed, 28 insertions(+), 15 deletions(-) diff --git a/web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx b/web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx index 75ba8362ae..b876adfa3d 100644 --- a/web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx +++ b/web/app/components/app/configuration/debug/debug-with-multiple-model/index.tsx @@ -99,7 +99,15 @@ const DebugWithMultipleModel = () => { }, [twoLine, threeLine, fourLine]) const setShowAppConfigureFeaturesModal = useAppStore(s => s.setShowAppConfigureFeaturesModal) - const inputsForm = modelConfig.configs.prompt_variables.filter(item => item.type !== 'api').map(item => ({ ...item, label: item.name, variable: item.key })) as InputForm[] + const inputsForm = modelConfig.configs.prompt_variables + .filter(item => item.type !== 'api') + .map(item => ({ + ...item, + label: item.name, + variable: item.key, + hide: item.hide ?? false, + required: item.required ?? false, + })) as InputForm[] return (
@@ -133,6 +141,7 @@ const DebugWithMultipleModel = () => { {isChatMode && (
= ({ { !noChatInput && ( icon?: string icon_background?: string + hide?: boolean // used in frontend to hide variable } export type CompletionParams = { From dd2725be686c14bfe139864505ca02d7a02bdb36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?= Date: Fri, 30 May 2025 10:52:38 +0800 Subject: [PATCH 09/73] fix: import from curl not work for --data (#20471) --- .../workflow/nodes/http/components/curl-panel.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/web/app/components/workflow/nodes/http/components/curl-panel.tsx b/web/app/components/workflow/nodes/http/components/curl-panel.tsx index 52e28d7336..a5339a1f39 100644 --- a/web/app/components/workflow/nodes/http/components/curl-panel.tsx +++ b/web/app/components/workflow/nodes/http/components/curl-panel.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react' import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' -import { BodyType, type HttpNodeType, Method } from '../types' +import { BodyPayloadValueType, BodyType, type HttpNodeType, Method } from '../types' import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' import Textarea from '@/app/components/base/textarea' @@ -51,11 +51,16 @@ const parseCurl = (curlCommand: string): { node: HttpNodeType | null; error: str case '-d': case '--data': case '--data-raw': - case '--data-binary': + case '--data-binary': { if (i + 1 >= args.length) return { node: null, error: 'Missing data value after -d, --data, --data-raw, or --data-binary.' } - node.body = { type: BodyType.rawText, data: args[++i].replace(/^['"]|['"]$/g, '') } + const bodyPayload = [{ + type: BodyPayloadValueType.text, + value: args[++i].replace(/^['"]|['"]$/g, ''), + }] + node.body = { type: BodyType.rawText, data: bodyPayload } break + } case '-F': case '--form': { if (i + 1 >= args.length) From d72d02b970eb3324290492ce06539adcc32c91bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 10:57:37 +0800 Subject: [PATCH 10/73] chore: translate i18n files (#20476) Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com> --- web/i18n/de-DE/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/de-DE/common.ts | 4 ++++ web/i18n/de-DE/login.ts | 5 +++++ web/i18n/de-DE/plugin.ts | 2 ++ web/i18n/de-DE/workflow.ts | 1 + web/i18n/es-ES/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/es-ES/common.ts | 3 +++ web/i18n/es-ES/login.ts | 5 +++++ web/i18n/es-ES/plugin.ts | 2 ++ web/i18n/es-ES/workflow.ts | 1 + web/i18n/fa-IR/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/fa-IR/common.ts | 4 ++++ web/i18n/fa-IR/login.ts | 5 +++++ web/i18n/fa-IR/plugin.ts | 2 ++ web/i18n/fa-IR/workflow.ts | 1 + web/i18n/fr-FR/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/fr-FR/common.ts | 4 ++++ web/i18n/fr-FR/dataset.ts | 1 + web/i18n/fr-FR/login.ts | 5 +++++ web/i18n/fr-FR/plugin.ts | 2 ++ web/i18n/fr-FR/workflow.ts | 1 + web/i18n/hi-IN/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/hi-IN/common.ts | 4 ++++ web/i18n/hi-IN/login.ts | 5 +++++ web/i18n/hi-IN/plugin.ts | 2 ++ web/i18n/hi-IN/workflow.ts | 1 + web/i18n/it-IT/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/it-IT/common.ts | 4 ++++ web/i18n/it-IT/login.ts | 5 +++++ web/i18n/it-IT/plugin.ts | 2 ++ web/i18n/it-IT/workflow.ts | 1 + web/i18n/ja-JP/common.ts | 1 + web/i18n/ja-JP/plugin.ts | 2 ++ web/i18n/ja-JP/workflow.ts | 1 + web/i18n/ko-KR/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/ko-KR/common.ts | 4 ++++ web/i18n/ko-KR/login.ts | 5 +++++ web/i18n/ko-KR/plugin.ts | 2 ++ web/i18n/ko-KR/workflow.ts | 1 + web/i18n/pl-PL/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/pl-PL/common.ts | 4 ++++ web/i18n/pl-PL/login.ts | 5 +++++ web/i18n/pl-PL/plugin.ts | 2 ++ web/i18n/pl-PL/workflow.ts | 1 + web/i18n/pt-BR/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/pt-BR/common.ts | 4 ++++ web/i18n/pt-BR/login.ts | 5 +++++ web/i18n/pt-BR/plugin.ts | 2 ++ web/i18n/pt-BR/workflow.ts | 1 + web/i18n/ro-RO/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/ro-RO/common.ts | 4 ++++ web/i18n/ro-RO/login.ts | 5 +++++ web/i18n/ro-RO/plugin.ts | 2 ++ web/i18n/ro-RO/workflow.ts | 1 + web/i18n/ru-RU/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/ru-RU/common.ts | 4 ++++ web/i18n/ru-RU/login.ts | 5 +++++ web/i18n/ru-RU/plugin.ts | 2 ++ web/i18n/ru-RU/workflow.ts | 1 + web/i18n/sl-SI/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/sl-SI/common.ts | 4 ++++ web/i18n/sl-SI/login.ts | 5 +++++ web/i18n/sl-SI/plugin.ts | 2 ++ web/i18n/sl-SI/workflow.ts | 1 + web/i18n/th-TH/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/th-TH/common.ts | 4 ++++ web/i18n/th-TH/login.ts | 5 +++++ web/i18n/th-TH/plugin.ts | 2 ++ web/i18n/th-TH/workflow.ts | 1 + web/i18n/tr-TR/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/tr-TR/common.ts | 4 ++++ web/i18n/tr-TR/login.ts | 5 +++++ web/i18n/tr-TR/plugin.ts | 2 ++ web/i18n/tr-TR/workflow.ts | 1 + web/i18n/uk-UA/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/uk-UA/common.ts | 4 ++++ web/i18n/uk-UA/login.ts | 5 +++++ web/i18n/uk-UA/plugin.ts | 2 ++ web/i18n/uk-UA/workflow.ts | 1 + web/i18n/vi-VN/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/vi-VN/common.ts | 4 ++++ web/i18n/vi-VN/login.ts | 5 +++++ web/i18n/vi-VN/plugin.ts | 2 ++ web/i18n/vi-VN/workflow.ts | 1 + web/i18n/zh-Hant/app.ts | 35 +++++++++++++++++++++++++++++++++++ web/i18n/zh-Hant/common.ts | 2 ++ web/i18n/zh-Hant/login.ts | 5 +++++ web/i18n/zh-Hant/plugin.ts | 1 + 88 files changed, 799 insertions(+) diff --git a/web/i18n/de-DE/app.ts b/web/i18n/de-DE/app.ts index 5ae5c39b51..b9fdde58ff 100644 --- a/web/i18n/de-DE/app.ts +++ b/web/i18n/de-DE/app.ts @@ -216,6 +216,41 @@ const translation = { moreFillTip: 'Maximal 10 Ebenen der Verschachtelung anzeigen', LLMResponse: 'LLM-Antwort', }, + accessItemsDescription: { + anyone: 'Jeder kann auf die Webanwendung zugreifen.', + specific: 'Nur bestimmte Gruppen oder Mitglieder können auf die Webanwendung zugreifen.', + organization: 'Jeder in der Organisation kann auf die Webanwendung zugreifen.', + }, + accessControlDialog: { + accessItems: { + anyone: 'Jeder mit dem Link', + specific: 'Spezifische Gruppen oder Mitglieder', + organization: 'Nur Mitglieder innerhalb des Unternehmens', + }, + operateGroupAndMember: { + searchPlaceholder: 'Gruppen und Mitglieder suchen', + allMembers: 'Alle Mitglieder', + expand: 'Erweitern', + noResult: 'Kein Ergebnis', + }, + title: 'Zugriffskontrolle für Webanwendungen', + description: 'Webanwendungszugriffsberechtigungen festlegen', + accessLabel: 'Wer hat Zugang', + groups_one: '{{count}} GRUPPE', + members_one: '{{count}} MITGLIED', + members_other: '{{count}} MITGLIEDER', + noGroupsOrMembers: 'Keine Gruppen oder Mitglieder ausgewählt', + webAppSSONotEnabledTip: 'Bitte kontaktieren Sie den Unternehmensadministrator, um die Authentifizierungsmethode der Webanwendung zu konfigurieren.', + updateSuccess: 'Erfolgreich aktualisiert', + groups_other: '{{count}} GRUPPEN', + }, + publishApp: { + title: 'Wer kann auf die Webanwendung zugreifen?', + notSetDesc: 'Derzeit kann niemand auf die Webanwendung zugreifen. Bitte setzen Sie die Berechtigungen.', + notSet: 'Nicht festgelegt', + }, + accessControl: 'Zugriffskontrolle für Webanwendungen', + noAccessPermission: 'Keine Berechtigung zum Zugriff auf die Webanwendung', } export default translation diff --git a/web/i18n/de-DE/common.ts b/web/i18n/de-DE/common.ts index 04fb06254a..3e00cfcaed 100644 --- a/web/i18n/de-DE/common.ts +++ b/web/i18n/de-DE/common.ts @@ -145,6 +145,8 @@ const translation = { newDataset: 'Wissen erstellen', tools: 'Werkzeuge', exploreMarketplace: 'Marketplace erkunden', + appDetail: 'App-Details', + account: 'Konto', }, userProfile: { settings: 'Einstellungen', @@ -644,6 +646,7 @@ const translation = { license: { expiring: 'Läuft an einem Tag ab', expiring_plural: 'Läuft in {{count}} Tagen ab', + unlimited: 'Unbegrenzt', }, pagination: { perPage: 'Artikel pro Seite', @@ -667,6 +670,7 @@ const translation = { browse: 'blättern', supportedFormats: 'Unterstützt PNG, JPG, JPEG, WEBP und GIF', }, + you: 'Du', } export default translation diff --git a/web/i18n/de-DE/login.ts b/web/i18n/de-DE/login.ts index 2e0d51cf85..23cd7ce11c 100644 --- a/web/i18n/de-DE/login.ts +++ b/web/i18n/de-DE/login.ts @@ -105,6 +105,11 @@ const translation = { licenseInactiveTip: 'Die Dify Enterprise-Lizenz für Ihren Arbeitsbereich ist inaktiv. Wenden Sie sich an Ihren Administrator, um Dify weiterhin zu verwenden.', licenseExpiredTip: 'Die Dify Enterprise-Lizenz für Ihren Arbeitsbereich ist abgelaufen. Wenden Sie sich an Ihren Administrator, um Dify weiterhin zu verwenden.', licenseLost: 'Lizenz verloren', + webapp: { + noLoginMethod: 'Authentifizierungsmethode ist nicht für die Webanwendung konfiguriert', + noLoginMethodTip: 'Bitte kontaktieren Sie den Systemadministrator, um eine Authentifizierungsmethode hinzuzufügen.', + disabled: 'Die Webanmeldeauthentifizierung ist deaktiviert. Bitte kontaktieren Sie den Systemadministrator, um sie zu aktivieren. Sie können versuchen, die App direkt zu verwenden.', + }, } export default translation diff --git a/web/i18n/de-DE/plugin.ts b/web/i18n/de-DE/plugin.ts index 9202c224de..498ac86573 100644 --- a/web/i18n/de-DE/plugin.ts +++ b/web/i18n/de-DE/plugin.ts @@ -62,6 +62,7 @@ const translation = { uninstalledTitle: 'Tool nicht installiert', toolLabel: 'Werkzeug', uninstalledContent: 'Dieses Plugin wird aus dem lokalen/GitHub-Repository installiert. Bitte nach der Installation verwenden.', + toolSetting: 'Werkzeugs Einstellungen', }, strategyNum: '{{num}} {{Strategie}} IINKLUSIVE', configureApp: 'App konfigurieren', @@ -210,6 +211,7 @@ const translation = { title: 'Plugins', }, difyVersionNotCompatible: 'Die aktuelle Dify-Version ist mit diesem Plugin nicht kompatibel, bitte aktualisieren Sie auf die erforderliche Mindestversion: {{minimalDifyVersion}}', + requestAPlugin: 'Ein Plugin anfordern', } export default translation diff --git a/web/i18n/de-DE/workflow.ts b/web/i18n/de-DE/workflow.ts index a87e58f75b..1eb7804271 100644 --- a/web/i18n/de-DE/workflow.ts +++ b/web/i18n/de-DE/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: 'von einem Tool generiertes JSON', }, + authorize: 'Autorisieren', }, questionClassifiers: { model: 'Modell', diff --git a/web/i18n/es-ES/app.ts b/web/i18n/es-ES/app.ts index de3a458d2b..c183485294 100644 --- a/web/i18n/es-ES/app.ts +++ b/web/i18n/es-ES/app.ts @@ -208,6 +208,41 @@ const translation = { structuredTip: 'Las Salidas Estructuradas son una función que garantiza que el modelo siempre generará respuestas que se ajusten a su esquema JSON proporcionado.', modelNotSupported: 'Modelo no soportado', }, + accessItemsDescription: { + anyone: 'Cualquiera puede acceder a la aplicación web.', + specific: 'Solo grupos o miembros específicos pueden acceder a la aplicación web', + organization: 'Cualquiera en la organización puede acceder a la aplicación web', + }, + accessControlDialog: { + accessItems: { + anyone: 'Cualquiera con el enlace', + specific: 'Grupos o miembros específicos', + organization: 'Solo miembros dentro de la empresa', + }, + operateGroupAndMember: { + searchPlaceholder: 'Buscar grupos y miembros', + allMembers: 'Todos los miembros', + expand: 'Expandir', + noResult: 'Sin resultado', + }, + title: 'Control de Acceso a la Aplicación Web', + description: 'Establecer permisos de acceso a la aplicación web', + accessLabel: '¿Quién tiene acceso?', + groups_one: '{{count}} GRUPO', + groups_other: '{{count}} GRUPOS', + members_one: '{{count}} MIEMBRO', + members_other: '{{count}} MIEMBROS', + noGroupsOrMembers: 'No grupos o miembros seleccionados', + webAppSSONotEnabledTip: 'Por favor, contacte al administrador de la empresa para configurar el método de autenticación de la aplicación web.', + updateSuccess: 'Actualización exitosa', + }, + publishApp: { + title: '¿Quién puede acceder a la aplicación web?', + notSet: 'No establecido', + notSetDesc: 'Actualmente nadie puede acceder a la aplicación web. Por favor, configure los permisos.', + }, + accessControl: 'Control de Acceso a la Aplicación Web', + noAccessPermission: 'No se permite el acceso a la aplicación web', } export default translation diff --git a/web/i18n/es-ES/common.ts b/web/i18n/es-ES/common.ts index ac8955a774..22c70f6bff 100644 --- a/web/i18n/es-ES/common.ts +++ b/web/i18n/es-ES/common.ts @@ -149,6 +149,8 @@ const translation = { newDataset: 'Crear Conocimiento', tools: 'Herramientas', exploreMarketplace: 'Explora el mercado', + appDetail: 'Detalles de la aplicación', + account: 'Cuenta', }, userProfile: { settings: 'Configuraciones', @@ -666,6 +668,7 @@ const translation = { browse: 'navegar', dropImageHere: 'Deja tu imagen aquí, o', }, + you: 'Tú', } export default translation diff --git a/web/i18n/es-ES/login.ts b/web/i18n/es-ES/login.ts index bb465ac1be..8c575e58ee 100644 --- a/web/i18n/es-ES/login.ts +++ b/web/i18n/es-ES/login.ts @@ -105,6 +105,11 @@ const translation = { licenseLost: 'Licencia perdida', licenseExpiredTip: 'La licencia de Dify Enterprise para su espacio de trabajo ha caducado. Póngase en contacto con su administrador para seguir utilizando Dify.', licenseLostTip: 'No se pudo conectar el servidor de licencias de Dife. Póngase en contacto con su administrador para seguir utilizando Dify.', + webapp: { + disabled: 'La autenticación de la aplicación web está desactivada. Por favor, contacte al administrador del sistema para habilitarla. Puede intentar usar la aplicación directamente.', + noLoginMethodTip: 'Por favor, contacta al administrador del sistema para agregar un método de autenticación.', + noLoginMethod: 'Método de autenticación no configurado para la aplicación web', + }, } export default translation diff --git a/web/i18n/es-ES/plugin.ts b/web/i18n/es-ES/plugin.ts index 3e62e185c3..4c1f148235 100644 --- a/web/i18n/es-ES/plugin.ts +++ b/web/i18n/es-ES/plugin.ts @@ -62,6 +62,7 @@ const translation = { unsupportedTitle: 'Acción no admitida', params: 'CONFIGURACIÓN DE RAZONAMIENTO', uninstalledLink: 'Administrar en Plugins', + toolSetting: 'Configuraciones de la herramienta', }, endpointDeleteContent: '¿Te gustaría eliminar {{nombre}}?', endpointDisableTip: 'Deshabilitar punto de conexión', @@ -210,6 +211,7 @@ const translation = { title: 'Complementos', }, difyVersionNotCompatible: 'La versión actual de Dify no es compatible con este plugin, por favor actualiza a la versión mínima requerida: {{minimalDifyVersion}}', + requestAPlugin: 'Solicitar un plugin', } export default translation diff --git a/web/i18n/es-ES/workflow.ts b/web/i18n/es-ES/workflow.ts index 4f98b6ace6..7881728c89 100644 --- a/web/i18n/es-ES/workflow.ts +++ b/web/i18n/es-ES/workflow.ts @@ -658,6 +658,7 @@ const translation = { }, json: 'JSON generado por la herramienta', }, + authorize: 'autorizar', }, questionClassifiers: { model: 'modelo', diff --git a/web/i18n/fa-IR/app.ts b/web/i18n/fa-IR/app.ts index f048dfca1f..d37f4e8f90 100644 --- a/web/i18n/fa-IR/app.ts +++ b/web/i18n/fa-IR/app.ts @@ -209,6 +209,41 @@ const translation = { modelNotSupportedTip: 'مدل فعلی این ویژگی را پشتیبانی نمی‌کند و به‌طور خودکار به تزریق درخواست تنزل پیدا می‌کند.', structuredTip: 'خروجی‌های ساختاری یک ویژگی است که تضمین می‌کند مدل همیشه پاسخ‌هایی تولید می‌کند که به طرح JSON ارائه شده شما پایبند باشد.', }, + accessItemsDescription: { + specific: 'فقط گروه‌ها یا اعضای خاصی می‌توانند به اپلیکیشن وب دسترسی پیدا کنند.', + anyone: 'هر کسی می‌تواند به وب‌اپلیکیشن دسترسی پیدا کند', + organization: 'هر کسی در سازمان می‌تواند به اپلیکیشن وب دسترسی پیدا کند.', + }, + accessControlDialog: { + accessItems: { + specific: 'گروه‌ها یا اعضای خاص', + organization: 'فقط اعضای داخل سازمان', + anyone: 'هر کسی که لینک را داشته باشد', + }, + operateGroupAndMember: { + searchPlaceholder: 'گروه‌ها و اعضا را جستجو کنید', + allMembers: 'تمام اعضا', + noResult: 'نتیجه‌ای نیست', + expand: 'گسترش', + }, + description: 'مجوزهای دسترسی به برنامه وب را تنظیم کنید', + accessLabel: 'چه کسی به آن دسترسی دارد', + groups_one: '{{count}} گروه', + groups_other: '{{count}} گروه', + members_one: '{{count}} عضو', + members_other: '{{count}} عضو', + noGroupsOrMembers: 'هیچ گروه یا عضوی انتخاب نشده است', + title: 'کنترل دسترسی به وب اپلیکیشن', + updateSuccess: 'به‌روز رسانی با موفقیت انجام شد', + webAppSSONotEnabledTip: 'لطفاً با مدیر شرکت تماس بگیرید تا روش احراز هویت برنامه وب را پیکربندی کند.', + }, + publishApp: { + notSet: 'تنظیم نشده است', + notSetDesc: 'در حال حاضر هیچ‌کس نمی‌تواند به برنامه وب دسترسی پیدا کند. لطفاً مجوزها را تنظیم کنید.', + title: 'چه کسی می‌تواند به برنامه وب دسترسی داشته باشد؟', + }, + accessControl: 'کنترل دسترسی به وب اپلیکیشن', + noAccessPermission: 'دسترسی به برنامه وب مجاز نیست', } export default translation diff --git a/web/i18n/fa-IR/common.ts b/web/i18n/fa-IR/common.ts index 64a5c3b73d..7cd9a89684 100644 --- a/web/i18n/fa-IR/common.ts +++ b/web/i18n/fa-IR/common.ts @@ -149,6 +149,8 @@ const translation = { newDataset: 'ایجاد دانش', tools: 'ابزارها', exploreMarketplace: 'بازار را کاوش کنید', + appDetail: 'جزئیات برنامه', + account: 'حساب', }, userProfile: { settings: 'تنظیمات', @@ -644,6 +646,7 @@ const translation = { license: { expiring_plural: 'انقضا در {{count}} روز', expiring: 'انقضا در یک روز', + unlimited: 'نامحدود', }, pagination: { perPage: 'موارد در هر صفحه', @@ -667,6 +670,7 @@ const translation = { supportedFormats: 'از فرمت‌های PNG، JPG، JPEG، WEBP و GIF پشتیبانی می‌کند', browse: 'مرورگر', }, + you: 'تو', } export default translation diff --git a/web/i18n/fa-IR/login.ts b/web/i18n/fa-IR/login.ts index 7394ab325f..7d853c7b2d 100644 --- a/web/i18n/fa-IR/login.ts +++ b/web/i18n/fa-IR/login.ts @@ -105,6 +105,11 @@ const translation = { licenseExpiredTip: 'مجوز Dify Enterprise برای فضای کاری شما منقضی شده است. لطفا برای ادامه استفاده از Dify با سرپرست خود تماس بگیرید.', licenseInactiveTip: 'مجوز Dify Enterprise برای فضای کاری شما غیرفعال است. لطفا برای ادامه استفاده از Dify با سرپرست خود تماس بگیرید.', licenseLostTip: 'اتصال سرور مجوز Dify انجام نشد. لطفا برای ادامه استفاده از Dify با سرپرست خود تماس بگیرید.', + webapp: { + disabled: 'احراز هویت وب اپ غیرفعال است. لطفاً با مدیر سیستم تماس بگیرید تا آن را فعال کند. می‌توانید سعی کنید مستقیماً از اپلیکیشن استفاده کنید.', + noLoginMethodTip: 'لطفاً با مدیر سیستم تماس بگیرید تا یک روش احراز هویت اضافه کند.', + noLoginMethod: 'روش احراز هویت برای برنامه وب پیکربندی نشده است', + }, } export default translation diff --git a/web/i18n/fa-IR/plugin.ts b/web/i18n/fa-IR/plugin.ts index 81aa61ae84..80433900c1 100644 --- a/web/i18n/fa-IR/plugin.ts +++ b/web/i18n/fa-IR/plugin.ts @@ -62,6 +62,7 @@ const translation = { uninstalledContent: 'این افزونه از مخزن local/GitHub نصب شده است. لطفا پس از نصب استفاده کنید.', unsupportedTitle: 'اکشن پشتیبانی نشده', unsupportedContent2: 'برای تغییر نسخه کلیک کنید.', + toolSetting: 'تنظیمات ابزار', }, endpointDeleteTip: 'حذف نقطه پایانی', disabled: 'غیر فعال', @@ -210,6 +211,7 @@ const translation = { title: 'پلاگین ها', }, difyVersionNotCompatible: 'نسخه فعلی دیفی با این پلاگین سازگار نیست، لطفاً به نسخه حداقل مورد نیاز به‌روزرسانی کنید: {{minimalDifyVersion}}', + requestAPlugin: 'درخواست یک افزونه', } export default translation diff --git a/web/i18n/fa-IR/workflow.ts b/web/i18n/fa-IR/workflow.ts index 4fb6ad8f37..e548dc8ecb 100644 --- a/web/i18n/fa-IR/workflow.ts +++ b/web/i18n/fa-IR/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: 'json تولید شده توسط ابزار', }, + authorize: 'مجوز دادن', }, questionClassifiers: { model: 'مدل', diff --git a/web/i18n/fr-FR/app.ts b/web/i18n/fr-FR/app.ts index beea355ffc..ffa00c758a 100644 --- a/web/i18n/fr-FR/app.ts +++ b/web/i18n/fr-FR/app.ts @@ -208,6 +208,41 @@ const translation = { moreFillTip: 'Affichage d\'un maximum de 10 niveaux d\'imbrication', configure: 'Configurer', }, + accessItemsDescription: { + anyone: 'Tout le monde peut accéder à l\'application web.', + specific: 'Seules des groupes ou membres spécifiques peuvent accéder à l\'application web.', + organization: 'Toute personne dans l\'organisation peut accéder à l\'application web.', + }, + accessControlDialog: { + accessItems: { + anyone: 'Quiconque avec le lien', + specific: 'Groupes ou membres spécifiques', + organization: 'Seuls les membres au sein de l\'entreprise', + }, + operateGroupAndMember: { + searchPlaceholder: 'Rechercher des groupes et des membres', + allMembers: 'Tous les membres', + expand: 'Développer', + noResult: 'Aucun résultat', + }, + title: 'Contrôle d\'accès à l\'application Web', + description: 'Définir les autorisations d\'accès à l\'application web', + accessLabel: 'Qui a accès', + groups_one: '{{count}} GROUPE', + groups_other: '{{count}} GROUPES', + members_one: '{{count}} MEMBRE', + members_other: '{{count}} MEMBRES', + noGroupsOrMembers: 'Aucun groupe ou membre sélectionné', + webAppSSONotEnabledTip: 'Veuillez contacter l\'administrateur de l\'entreprise pour configurer la méthode d\'authentification de l\'application web.', + updateSuccess: 'Mise à jour réussie', + }, + publishApp: { + title: 'Qui peut accéder à l\'application web', + notSet: 'Non défini', + notSetDesc: 'Actuellement, personne ne peut accéder à l\'application web. Veuillez définir les autorisations.', + }, + accessControl: 'Contrôle d\'accès à l\'application Web', + noAccessPermission: 'Pas de permission d\'accéder à l\'application web', } export default translation diff --git a/web/i18n/fr-FR/common.ts b/web/i18n/fr-FR/common.ts index 9ba5e8103c..f08ef40c4d 100644 --- a/web/i18n/fr-FR/common.ts +++ b/web/i18n/fr-FR/common.ts @@ -145,6 +145,8 @@ const translation = { newDataset: 'Créer des Connaissances', tools: 'Outils', exploreMarketplace: 'Explorer Marketplace', + appDetail: 'Détails de l\'application', + account: 'Compte', }, userProfile: { settings: 'Paramètres', @@ -644,6 +646,7 @@ const translation = { license: { expiring: 'Expirant dans un jour', expiring_plural: 'Expirant dans {{count}} jours', + unlimited: 'Illimité', }, pagination: { perPage: 'Articles par page', @@ -667,6 +670,7 @@ const translation = { dropImageHere: 'Déposez votre image ici, ou', supportedFormats: 'Prend en charge PNG, JPG, JPEG, WEBP et GIF', }, + you: 'Vous', } export default translation diff --git a/web/i18n/fr-FR/dataset.ts b/web/i18n/fr-FR/dataset.ts index ba2985ca2b..c9739e20a1 100644 --- a/web/i18n/fr-FR/dataset.ts +++ b/web/i18n/fr-FR/dataset.ts @@ -203,6 +203,7 @@ const translation = { values: '{{num}} Valeurs', deleteContent: 'Êtes-vous sûr de vouloir supprimer les métadonnées "{{name}}" ?', name: 'Nom', + disabled: 'handicapés', }, documentMetadata: { technicalParameters: 'Paramètres techniques', diff --git a/web/i18n/fr-FR/login.ts b/web/i18n/fr-FR/login.ts index a7a633f330..68a642b3ea 100644 --- a/web/i18n/fr-FR/login.ts +++ b/web/i18n/fr-FR/login.ts @@ -105,6 +105,11 @@ const translation = { licenseLost: 'Licence perdue', licenseExpiredTip: 'La licence Dify Enterprise de votre espace de travail a expiré. Veuillez contacter votre administrateur pour continuer à utiliser Dify.', licenseInactive: 'Licence inactive', + webapp: { + noLoginMethodTip: 'Veuillez contacter l\'administrateur système pour ajouter une méthode d\'authentification.', + noLoginMethod: 'Méthode d\'authentification non configurée pour l\'application web', + disabled: 'L\'authentification de l\'application web est désactivée. Veuillez contacter l\'administrateur du système pour l\'activer. Vous pouvez essayer d\'utiliser l\'application directement.', + }, } export default translation diff --git a/web/i18n/fr-FR/plugin.ts b/web/i18n/fr-FR/plugin.ts index 04269e75ed..52930bd249 100644 --- a/web/i18n/fr-FR/plugin.ts +++ b/web/i18n/fr-FR/plugin.ts @@ -62,6 +62,7 @@ const translation = { settings: 'PARAMÈTRES UTILISATEUR', paramsTip2: 'Lorsque « Automatique » est désactivé, la valeur par défaut est utilisée.', paramsTip1: 'Contrôle les paramètres d’inférence LLM.', + toolSetting: 'Paramètres de l\'outil', }, modelNum: '{{num}} MODÈLES INCLUS', endpointDeleteTip: 'Supprimer le point de terminaison', @@ -210,6 +211,7 @@ const translation = { title: 'Plugins', }, difyVersionNotCompatible: 'La version actuelle de Dify n\'est pas compatible avec ce plugin, veuillez mettre à niveau vers la version minimale requise : {{minimalDifyVersion}}', + requestAPlugin: 'Demander un plugin', } export default translation diff --git a/web/i18n/fr-FR/workflow.ts b/web/i18n/fr-FR/workflow.ts index 12061705de..7a15bcaa4d 100644 --- a/web/i18n/fr-FR/workflow.ts +++ b/web/i18n/fr-FR/workflow.ts @@ -659,6 +659,7 @@ const translation = { }, json: 'JSON généré par un outil', }, + authorize: 'Autoriser', }, questionClassifiers: { model: 'modèle', diff --git a/web/i18n/hi-IN/app.ts b/web/i18n/hi-IN/app.ts index e5db983f45..f9486b93ec 100644 --- a/web/i18n/hi-IN/app.ts +++ b/web/i18n/hi-IN/app.ts @@ -209,6 +209,41 @@ const translation = { structuredTip: 'संरचित आउटपुट एक विशेषता है जो यह सुनिश्चित करती है कि मॉडल हमेशा आपके प्रदान किए गए JSON स्कीमा के अनुसार प्रतिक्रियाएँ生成 करेगा।', modelNotSupportedTip: 'वर्तमान मॉडल इस सुविधा का समर्थन नहीं करता है और स्वचालित रूप से प्रॉम्प्ट इंजेक्शन में डाउनग्रेड किया जाता है।', }, + accessItemsDescription: { + anyone: 'कोई भी वेब ऐप तक पहुँच सकता है', + organization: 'संस्थान के किसी भी व्यक्ति को वेब ऐप तक पहुंच प्राप्त है', + specific: 'केवल विशेष समूह या सदस्य ही वेब ऐप तक पहुंच सकते हैं', + }, + accessControlDialog: { + accessItems: { + anyone: 'लिंक के साथ कोई भी', + specific: 'विशिष्ट समूह या सदस्य', + organization: 'केवल उद्यम के भीतर के सदस्य', + }, + operateGroupAndMember: { + searchPlaceholder: 'समूहों और सदस्यों की खोज करें', + allMembers: 'सभी सदस्य', + expand: 'व्याप्त करें', + noResult: 'कोई परिणाम नहीं', + }, + title: 'वेब एप्लिकेशन पहुँच नियंत्रण', + description: 'वेब ऐप एक्सेस अनुमतियाँ सेट करें', + groups_one: '{{count}} समूह', + groups_other: '{{count}} समूह', + members_one: '{{count}} सदस्य', + members_other: '{{count}} सदस्य', + noGroupsOrMembers: 'कोई समूह या सदस्य चयनित नहीं किया गया', + updateSuccess: 'सफलता से अपडेट किया गया', + accessLabel: 'किसके पास पहुँच है', + webAppSSONotEnabledTip: 'कृपया वेब ऐप प्रमाणीकरण विधि कॉन्फ़िगर करने के लिए उद्यम प्रशासक से संपर्क करें।', + }, + publishApp: { + title: 'वेब ऐप तक कौन पहुँच सकता है', + notSet: 'अनुबंधित नहीं किया गया', + notSetDesc: 'वर्तमान में कोई भी वेब ऐप तक पहुंच नहीं बना सकता। कृपया अनुमतियाँ सेट करें।', + }, + accessControl: 'वेब एप्लिकेशन पहुँच नियंत्रण', + noAccessPermission: 'वेब एप्लिकेशन तक पहुँचने की अनुमति नहीं है', } export default translation diff --git a/web/i18n/hi-IN/common.ts b/web/i18n/hi-IN/common.ts index 4964bcbcc4..65565f9955 100644 --- a/web/i18n/hi-IN/common.ts +++ b/web/i18n/hi-IN/common.ts @@ -154,6 +154,8 @@ const translation = { newDataset: 'ज्ञान बनाएं', tools: 'उपकरण', exploreMarketplace: 'मार्केटप्लेस का अन्वेषण करें', + appDetail: 'ऐप विवरण', + account: 'खाता', }, userProfile: { settings: 'सेटिंग्स', @@ -666,6 +668,7 @@ const translation = { license: { expiring: 'एक दिन में समाप्त हो रहा है', expiring_plural: '{{गिनती}} दिनों में समाप्त हो रहा है', + unlimited: 'असीमित', }, pagination: { perPage: 'प्रति पृष्ठ आइटम', @@ -689,6 +692,7 @@ const translation = { browse: 'ब्राउज़ करें', dropImageHere: 'अपनी छवि यहाँ छोड़ें, या', }, + you: 'आप', } export default translation diff --git a/web/i18n/hi-IN/login.ts b/web/i18n/hi-IN/login.ts index 0be8cbc3ab..0c9f4451b6 100644 --- a/web/i18n/hi-IN/login.ts +++ b/web/i18n/hi-IN/login.ts @@ -110,6 +110,11 @@ const translation = { licenseLostTip: 'Dify लायसेंस सर्वर से कनेक्ट करने में विफल. Dify का उपयोग जारी रखने के लिए कृपया अपने व्यवस्थापक से संपर्क करें.', licenseInactiveTip: 'आपके कार्यस्थल के लिए डिफाई एंटरप्राइज लाइसेंस निष्क्रिय है। कृपया डिफाई का उपयोग जारी रखने के लिए अपने प्रशासक से संपर्क करें।', licenseExpiredTip: 'आपके कार्यस्थल के लिए डिफाई एंटरप्राइज लाइसेंस समाप्त हो गया है। कृपया डिफाई का उपयोग जारी रखने के लिए अपने प्रशासक से संपर्क करें।', + webapp: { + noLoginMethodTip: 'कृपया एक प्रमाणीकरण विधि जोड़ने के लिए सिस्टम प्रशासक से संपर्क करें।', + noLoginMethod: 'वेब ऐप के लिए प्रमाणीकरण विधि कॉन्फ़िगर नहीं की गई है', + disabled: 'वेब ऐप प्रमाणीकरण अक्षम है। कृपया इसे सक्षम करने के लिए सिस्टम प्रशासक से संपर्क करें। आप सीधे ऐप का उपयोग करने की कोशिश कर सकते हैं।', + }, } export default translation diff --git a/web/i18n/hi-IN/plugin.ts b/web/i18n/hi-IN/plugin.ts index 075e9a1da4..76eb84246a 100644 --- a/web/i18n/hi-IN/plugin.ts +++ b/web/i18n/hi-IN/plugin.ts @@ -62,6 +62,7 @@ const translation = { paramsTip2: 'जब \'स्वचालित\' बंद होता है, तो डिफ़ॉल्ट मान का उपयोग किया जाता है।', descriptionPlaceholder: 'उपकरण के उद्देश्य का संक्षिप्त विवरण, जैसे, किसी विशेष स्थान के लिए तापमान प्राप्त करना।', paramsTip1: 'एलएलएम अनुमान पैरामीटर को नियंत्रित करता है।', + toolSetting: 'टूल सेटिंग्स', }, switchVersion: 'स्विच संस्करण', endpointModalDesc: 'एक बार कॉन्फ़िगर होने के बाद, प्लगइन द्वारा API एंडपॉइंट्स के माध्यम से प्रदान की गई सुविधाओं का उपयोग किया जा सकता है।', @@ -210,6 +211,7 @@ const translation = { title: 'प्लगइन्स', }, difyVersionNotCompatible: 'वर्तमान डिफाई संस्करण इस प्लगइन के साथ संगत नहीं है, कृपया आवश्यक न्यूनतम संस्करण में अपग्रेड करें: {{minimalDifyVersion}}', + requestAPlugin: 'एक प्लगइन का अनुरोध करें', } export default translation diff --git a/web/i18n/hi-IN/workflow.ts b/web/i18n/hi-IN/workflow.ts index 8d8c929156..c295b16603 100644 --- a/web/i18n/hi-IN/workflow.ts +++ b/web/i18n/hi-IN/workflow.ts @@ -676,6 +676,7 @@ const translation = { }, json: 'उपकरण द्वारा उत्पन्न JSON', }, + authorize: 'अधिकृत करें', }, questionClassifiers: { model: 'मॉडल', diff --git a/web/i18n/it-IT/app.ts b/web/i18n/it-IT/app.ts index a1762bdea2..f6855873db 100644 --- a/web/i18n/it-IT/app.ts +++ b/web/i18n/it-IT/app.ts @@ -220,6 +220,41 @@ const translation = { notConfiguredTip: 'L\'output strutturato non è stato ancora configurato.', modelNotSupportedTip: 'Il modello attuale non supporta questa funzione e viene automaticamente downgradato a iniezione di prompt.', }, + accessItemsDescription: { + anyone: 'Chiunque può accedere all\'app web', + specific: 'Solo gruppi o membri specifici possono accedere all\'app web.', + organization: 'Qualsiasi persona nell\'organizzazione può accedere all\'app web', + }, + accessControlDialog: { + accessItems: { + anyone: 'Chiunque con il link', + specific: 'Gruppi o membri specifici', + organization: 'Solo i membri all\'interno dell\'impresa', + }, + operateGroupAndMember: { + searchPlaceholder: 'Cerca gruppi e membri', + allMembers: 'Tutti i membri', + expand: 'Espandere', + noResult: 'Nessun risultato', + }, + title: 'Controllo di accesso all\'app web', + description: 'Imposta le autorizzazioni di accesso all\'app web', + accessLabel: 'Chi ha accesso', + groups_one: '{{count}} GRUPPO', + groups_other: '{{count}} GRUPPI', + members_one: '{{count}} MEMBRO', + members_other: '{{count}} MEMBRI', + noGroupsOrMembers: 'Nessun gruppo o membro selezionato', + webAppSSONotEnabledTip: 'Si prega di contattare l\'amministratore dell\'impresa per configurare il metodo di autenticazione dell\'app web.', + updateSuccess: 'Aggiornamento avvenuto con successo', + }, + publishApp: { + title: 'Chi può accedere all\'app web', + notSet: 'Non impostato', + notSetDesc: 'Attualmente nessuno può accedere all\'app web. Si prega di impostare i permessi.', + }, + accessControl: 'Controllo di accesso all\'app web', + noAccessPermission: 'Nessun permesso per accedere all\'app web', } export default translation diff --git a/web/i18n/it-IT/common.ts b/web/i18n/it-IT/common.ts index 2530ee16a4..b47bb23854 100644 --- a/web/i18n/it-IT/common.ts +++ b/web/i18n/it-IT/common.ts @@ -154,6 +154,8 @@ const translation = { newDataset: 'Crea Conoscenza', tools: 'Strumenti', exploreMarketplace: 'Esplora il Marketplace', + appDetail: 'Dettagli dell\'app', + account: 'Account', }, userProfile: { settings: 'Impostazioni', @@ -675,6 +677,7 @@ const translation = { license: { expiring_plural: 'Scadenza tra {{count}} giorni', expiring: 'Scadenza in un giorno', + unlimited: 'Illimitato', }, pagination: { perPage: 'Articoli per pagina', @@ -698,6 +701,7 @@ const translation = { browse: 'sfogliare', dropImageHere: 'Trascina la tua immagine qui, oppure', }, + you: 'Tu', } export default translation diff --git a/web/i18n/it-IT/login.ts b/web/i18n/it-IT/login.ts index 350424259e..cbc05d60c1 100644 --- a/web/i18n/it-IT/login.ts +++ b/web/i18n/it-IT/login.ts @@ -115,6 +115,11 @@ const translation = { licenseExpiredTip: 'La licenza Dify Enterprise per la tua area di lavoro è scaduta. Contatta il tuo amministratore per continuare a utilizzare Dify.', licenseInactiveTip: 'La licenza Dify Enterprise per la tua area di lavoro è inattiva. Contatta il tuo amministratore per continuare a utilizzare Dify.', licenseInactive: 'Licenza inattiva', + webapp: { + noLoginMethod: 'Metodo di autenticazione non configurato per l\'app web', + noLoginMethodTip: 'Si prega di contattare l\'amministratore del sistema per aggiungere un metodo di autenticazione.', + disabled: 'L\'autenticazione dell\'app web è disabilitata. Si prega di contattare l\'amministratore di sistema per abilitarla. Puoi provare a utilizzare l\'app direttamente.', + }, } export default translation diff --git a/web/i18n/it-IT/plugin.ts b/web/i18n/it-IT/plugin.ts index 2832776b9d..1c84b61fda 100644 --- a/web/i18n/it-IT/plugin.ts +++ b/web/i18n/it-IT/plugin.ts @@ -62,6 +62,7 @@ const translation = { descriptionLabel: 'Descrizione dell\'utensile', auto: 'Automatico', paramsTip2: 'Quando \'Automatico\' è disattivato, viene utilizzato il valore predefinito.', + toolSetting: 'Impostazioni degli strumenti', }, modelNum: '{{num}} MODELLI INCLUSI', endpointModalTitle: 'Endpoint di configurazione', @@ -210,6 +211,7 @@ const translation = { title: 'Plugin', }, difyVersionNotCompatible: 'L\'attuale versione di Dify non è compatibile con questo plugin, si prega di aggiornare alla versione minima richiesta: {{minimalDifyVersion}}', + requestAPlugin: 'Richiedi un plugin', } export default translation diff --git a/web/i18n/it-IT/workflow.ts b/web/i18n/it-IT/workflow.ts index 532dbec3b0..26c790f4a0 100644 --- a/web/i18n/it-IT/workflow.ts +++ b/web/i18n/it-IT/workflow.ts @@ -679,6 +679,7 @@ const translation = { }, json: 'json generato dallo strumento', }, + authorize: 'Autorizza', }, questionClassifiers: { model: 'modello', diff --git a/web/i18n/ja-JP/common.ts b/web/i18n/ja-JP/common.ts index cd96ff89b3..882e00cec8 100644 --- a/web/i18n/ja-JP/common.ts +++ b/web/i18n/ja-JP/common.ts @@ -660,6 +660,7 @@ const translation = { license: { expiring_plural: '有効期限 {{count}} 日', expiring: '1日で有効期限が切れます', + unlimited: '無制限', }, pagination: { perPage: 'ページあたりのアイテム数', diff --git a/web/i18n/ja-JP/plugin.ts b/web/i18n/ja-JP/plugin.ts index 6a27048797..dfb4efe679 100644 --- a/web/i18n/ja-JP/plugin.ts +++ b/web/i18n/ja-JP/plugin.ts @@ -62,6 +62,7 @@ const translation = { paramsTip1: 'LLM推論パラメータを制御します。', toolLabel: '道具', unsupportedTitle: 'サポートされていないアクション', + toolSetting: 'ツール設定', }, endpointDisableTip: 'エンドポイントを無効にする', endpointModalDesc: '設定が完了すると、APIエンドポイントを介してプラグインが提供する機能を使用できます。', @@ -210,6 +211,7 @@ const translation = { metadata: { title: 'プラグイン', }, + requestAPlugin: 'プラグインをリクエストする', } export default translation diff --git a/web/i18n/ja-JP/workflow.ts b/web/i18n/ja-JP/workflow.ts index 3c3e8342a7..8495a7dfd5 100644 --- a/web/i18n/ja-JP/workflow.ts +++ b/web/i18n/ja-JP/workflow.ts @@ -666,6 +666,7 @@ const translation = { }, json: 'ツールで生成されたJSON', }, + authorize: '認証する', }, questionClassifiers: { model: 'モデル', diff --git a/web/i18n/ko-KR/app.ts b/web/i18n/ko-KR/app.ts index b4ee4cf6ac..d800968eaa 100644 --- a/web/i18n/ko-KR/app.ts +++ b/web/i18n/ko-KR/app.ts @@ -205,6 +205,41 @@ const translation = { modelNotSupportedTip: '현재 모델은 이 기능을 지원하지 않으며 자동으로 프롬프트 주입으로 다운그레이드됩니다.', structuredTip: '구조화된 출력은 모델이 제공한 JSON 스키마를 항상 준수하는 응답을 생성하도록 보장하는 기능입니다.', }, + accessItemsDescription: { + anyone: '누구나 웹 앱에 접근할 수 있습니다.', + specific: '특정 그룹이나 회원만 웹 앱에 접근할 수 있습니다.', + organization: '조직 내 모든 사람이 웹 애플리케이션에 접근할 수 있습니다.', + }, + accessControlDialog: { + accessItems: { + anyone: '링크가 있는 누구나', + specific: '특정 그룹 또는 구성원', + organization: '기업 내의 회원만', + }, + operateGroupAndMember: { + searchPlaceholder: '그룹 및 구성원 검색', + allMembers: '모든 멤버들', + expand: '확장하다', + noResult: '결과 없음', + }, + title: '웹 애플리케이션 접근 제어', + accessLabel: '누가 접근할 수 있습니까?', + groups_one: '{{count}} 그룹', + groups_other: '{{count}} 그룹', + members_one: '{{count}} 회원', + members_other: '{{count}} 회원', + noGroupsOrMembers: '선택된 그룹 또는 멤버가 없습니다.', + webAppSSONotEnabledTip: '웹 앱 인증 방법을 구성하려면 엔터프라이즈 관리자인에게 문의하십시오.', + updateSuccess: '업데이트가 성공적으로 완료되었습니다.', + description: '웹 앱 접근 권한 설정', + }, + publishApp: { + title: '누가 웹 애플리케이션에 접근할 수 있나요?', + notSet: '설정되지 않음', + notSetDesc: '현재 아무도 웹 앱에 접근할 수 없습니다. 권한을 설정해 주세요.', + }, + accessControl: '웹 애플리케이션 접근 제어', + noAccessPermission: '웹 앱에 대한 접근 권한이 없습니다.', } export default translation diff --git a/web/i18n/ko-KR/common.ts b/web/i18n/ko-KR/common.ts index 1d31761ebb..4fa8ec74e4 100644 --- a/web/i18n/ko-KR/common.ts +++ b/web/i18n/ko-KR/common.ts @@ -141,6 +141,8 @@ const translation = { newDataset: '지식 만들기', tools: '도구', exploreMarketplace: 'Marketplace 둘러보기', + appDetail: '앱 세부정보', + account: '계정', }, userProfile: { settings: '설정', @@ -640,6 +642,7 @@ const translation = { license: { expiring_plural: '{{count}}일 후에 만료', expiring: '하루 후에 만료', + unlimited: '무제한', }, pagination: { perPage: '페이지당 항목 수', @@ -663,6 +666,7 @@ const translation = { browse: '브라우즈', dropImageHere: '여기에 이미지를 드롭하거나', }, + you: '너', } export default translation diff --git a/web/i18n/ko-KR/login.ts b/web/i18n/ko-KR/login.ts index 05a60c7b68..4fbd5f5522 100644 --- a/web/i18n/ko-KR/login.ts +++ b/web/i18n/ko-KR/login.ts @@ -105,6 +105,11 @@ const translation = { licenseInactive: 'License Inactive(라이선스 비활성)', licenseExpired: '라이센스가 만료되었습니다.', licenseExpiredTip: '작업 영역에 대한 Dify Enterprise 라이선스가 만료되었습니다. Dify를 계속 사용하려면 관리자에게 문의하십시오.', + webapp: { + noLoginMethod: '웹 애플리케이션에 대한 인증 방법이 구성되어 있지 않습니다.', + disabled: '웹앱 인증이 비활성화되었습니다. 이를 활성화하려면 시스템 관리자에게 문의하십시오. 앱을 직접 사용해 볼 수 있습니다.', + noLoginMethodTip: '인증 방법을 추가하려면 시스템 관리자에게 연락하십시오.', + }, } export default translation diff --git a/web/i18n/ko-KR/plugin.ts b/web/i18n/ko-KR/plugin.ts index fd3603a07f..8d823136d0 100644 --- a/web/i18n/ko-KR/plugin.ts +++ b/web/i18n/ko-KR/plugin.ts @@ -62,6 +62,7 @@ const translation = { placeholder: '도구 선택...', paramsTip2: '\'자동\'이 꺼져 있으면 기본값이 사용됩니다.', unsupportedContent: '설치된 플러그인 버전은 이 작업을 제공하지 않습니다.', + toolSetting: '도구 설정', }, configureApp: '앱 구성', strategyNum: '{{번호}} {{전략}} 포함', @@ -210,6 +211,7 @@ const translation = { title: '플러그인', }, difyVersionNotCompatible: '현재 Dify 버전이 이 플러그인과 호환되지 않습니다. 필요한 최소 버전으로 업그레이드하십시오: {{minimalDifyVersion}}', + requestAPlugin: '플러그인을 요청하세요', } export default translation diff --git a/web/i18n/ko-KR/workflow.ts b/web/i18n/ko-KR/workflow.ts index b2c3e2d422..3cf22dfe13 100644 --- a/web/i18n/ko-KR/workflow.ts +++ b/web/i18n/ko-KR/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: '도구로 생성된 JSON', }, + authorize: '권한 부여', }, questionClassifiers: { model: '모델', diff --git a/web/i18n/pl-PL/app.ts b/web/i18n/pl-PL/app.ts index c60b34f860..54759154ca 100644 --- a/web/i18n/pl-PL/app.ts +++ b/web/i18n/pl-PL/app.ts @@ -216,6 +216,41 @@ const translation = { modelNotSupported: 'Model nie jest obsługiwany', modelNotSupportedTip: 'Aktualny model nie obsługuje tej funkcji i zostaje automatycznie obniżony do wstrzyknięcia zapytania.', }, + accessItemsDescription: { + anyone: 'Każdy może uzyskać dostęp do aplikacji webowej', + specific: 'Tylko określone grupy lub członkowie mogą uzyskać dostęp do aplikacji internetowej', + organization: 'Każdy w organizacji ma dostęp do aplikacji internetowej.', + }, + accessControlDialog: { + accessItems: { + anyone: 'Każdy z linkiem', + specific: 'Specyficzne grupy lub członkowie', + organization: 'Tylko członkowie w obrębie przedsiębiorstwa', + }, + operateGroupAndMember: { + searchPlaceholder: 'Szukaj grup i członków', + allMembers: 'Wszyscy członkowie', + expand: 'Rozszerz', + noResult: 'Brak wyniku', + }, + title: 'Kontrola dostępu do aplikacji internetowej', + description: 'Ustaw uprawnienia dostępu do aplikacji webowej', + accessLabel: 'Kto ma dostęp', + groups_one: '{{count}} GRUPA', + groups_other: '{{count}} GRUPY', + members_one: '{{count}} CZŁONEK', + members_other: '{{count}} CZŁONKÓW', + noGroupsOrMembers: 'Nie wybrano żadnych grup ani członków', + webAppSSONotEnabledTip: 'Proszę skontaktować się z administratorem przedsiębiorstwa, aby skonfigurować metodę uwierzytelniania aplikacji internetowej.', + updateSuccess: 'Aktualizacja powiodła się', + }, + publishApp: { + title: 'Kto ma dostęp do aplikacji internetowej', + notSet: 'Nie ustawiono', + notSetDesc: 'Obecnie nikt nie może uzyskać dostępu do aplikacji internetowej. Proszę ustawić uprawnienia.', + }, + accessControl: 'Kontrola dostępu do aplikacji internetowej', + noAccessPermission: 'Brak uprawnień do dostępu do aplikacji internetowej', } export default translation diff --git a/web/i18n/pl-PL/common.ts b/web/i18n/pl-PL/common.ts index 19aa6448bf..e081a1ed9e 100644 --- a/web/i18n/pl-PL/common.ts +++ b/web/i18n/pl-PL/common.ts @@ -150,6 +150,8 @@ const translation = { newDataset: 'Utwórz Wiedzę', tools: 'Narzędzia', exploreMarketplace: 'Zapoznaj się z Marketplace', + appDetail: 'Szczegóły aplikacji', + account: 'klient', }, userProfile: { settings: 'Ustawienia', @@ -662,6 +664,7 @@ const translation = { license: { expiring_plural: 'Wygasa za {{count}} dni', expiring: 'Wygasa w ciągu jednego dnia', + unlimited: 'Nieograniczony', }, pagination: { perPage: 'Ilość elementów na stronie', @@ -685,6 +688,7 @@ const translation = { browse: 'przeglądaj', supportedFormats: 'Obsługuje PNG, JPG, JPEG, WEBP i GIF', }, + you: 'Ty', } export default translation diff --git a/web/i18n/pl-PL/login.ts b/web/i18n/pl-PL/login.ts index 99719fe71a..b1bb0b93c6 100644 --- a/web/i18n/pl-PL/login.ts +++ b/web/i18n/pl-PL/login.ts @@ -110,6 +110,11 @@ const translation = { licenseExpiredTip: 'Licencja Dify Enterprise dla Twojego obszaru roboczego wygasła. Skontaktuj się z administratorem, aby kontynuować korzystanie z Dify.', licenseLostTip: 'Nie udało się nawiązać połączenia z serwerem licencji Dify. Skontaktuj się z administratorem, aby kontynuować korzystanie z Dify.', licenseInactiveTip: 'Licencja Dify Enterprise dla Twojego obszaru roboczego jest nieaktywna. Skontaktuj się z administratorem, aby kontynuować korzystanie z Dify.', + webapp: { + noLoginMethod: 'Metoda uwierzytelniania nie jest skonfigurowana dla aplikacji internetowej', + noLoginMethodTip: 'Proszę skontaktować się z administratorem systemu, aby dodać metodę uwierzytelniania.', + disabled: 'Uwierzytelnianie aplikacji internetowej jest wyłączone. Proszę skontaktować się z administratorem systemu, aby je włączyć. Możesz spróbować użyć aplikacji bezpośrednio.', + }, } export default translation diff --git a/web/i18n/pl-PL/plugin.ts b/web/i18n/pl-PL/plugin.ts index 0883a98e07..f02575919e 100644 --- a/web/i18n/pl-PL/plugin.ts +++ b/web/i18n/pl-PL/plugin.ts @@ -62,6 +62,7 @@ const translation = { uninstalledTitle: 'Narzędzie nie jest zainstalowane', paramsTip2: 'Gdy opcja "Automatycznie" jest wyłączona, używana jest wartość domyślna.', toolLabel: 'Narzędzie', + toolSetting: 'Ustawienia narzędzi', }, strategyNum: '{{liczba}} {{strategia}} ZAWARTE', endpointsEmpty: 'Kliknij przycisk "+", aby dodać punkt końcowy', @@ -210,6 +211,7 @@ const translation = { title: 'Wtyczki', }, difyVersionNotCompatible: 'Obecna wersja Dify nie jest kompatybilna z tym wtyczką, proszę zaktualizować do minimalnej wymaganej wersji: {{minimalDifyVersion}}', + requestAPlugin: 'Poproś o wtyczkę', } export default translation diff --git a/web/i18n/pl-PL/workflow.ts b/web/i18n/pl-PL/workflow.ts index 0b8b12aa2c..c91af84e3a 100644 --- a/web/i18n/pl-PL/workflow.ts +++ b/web/i18n/pl-PL/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: 'JSON wygenerowany przez narzędzien', }, + authorize: 'Autoryzuj', }, questionClassifiers: { model: 'model', diff --git a/web/i18n/pt-BR/app.ts b/web/i18n/pt-BR/app.ts index 9e48b72895..5dd1753cac 100644 --- a/web/i18n/pt-BR/app.ts +++ b/web/i18n/pt-BR/app.ts @@ -209,6 +209,41 @@ const translation = { moreFillTip: 'Mostrando um máximo de 10 níveis de aninhamento', notConfiguredTip: 'A saída estruturada ainda não foi configurada.', }, + accessItemsDescription: { + anyone: 'Qualquer pessoa pode acessar o aplicativo web', + specific: 'Apenas grupos ou membros específicos podem acessar o aplicativo web', + organization: 'Qualquer pessoa na organização pode acessar o aplicativo web', + }, + accessControlDialog: { + accessItems: { + anyone: 'Qualquer pessoa com o link', + specific: 'Grupos específicos ou membros', + organization: 'Apenas membros dentro da empresa', + }, + operateGroupAndMember: { + searchPlaceholder: 'Pesquisar grupos e membros', + allMembers: 'Todos os membros', + expand: 'Expandir', + noResult: 'Nenhum resultado', + }, + title: 'Controle de Acesso do Aplicativo Web', + description: 'Defina as permissões de acesso do aplicativo da web', + accessLabel: 'Quem tem acesso', + groups_one: '{{count}} GRUPO', + groups_other: '{{count}} GRUPOS', + members_other: '{{count}} MEMBROS', + noGroupsOrMembers: 'Nenhum grupo ou membro selecionado', + updateSuccess: 'Atualização bem-sucedida', + members_one: '{{count}} MEMBRO', + webAppSSONotEnabledTip: 'Por favor, entre em contato com o administrador da empresa para configurar o método de autenticação da aplicação web.', + }, + publishApp: { + title: 'Quem pode acessar o aplicativo web', + notSet: 'Não definido', + notSetDesc: 'Atualmente, ninguém pode acessar o aplicativo web. Por favor, defina as permissões.', + }, + accessControl: 'Controle de Acesso do Aplicativo Web', + noAccessPermission: 'Sem permissão para acessar o aplicativo web', } export default translation diff --git a/web/i18n/pt-BR/common.ts b/web/i18n/pt-BR/common.ts index 3e059b1a1d..d9409b5dd0 100644 --- a/web/i18n/pt-BR/common.ts +++ b/web/i18n/pt-BR/common.ts @@ -145,6 +145,8 @@ const translation = { newDataset: 'Criar Conhecimento', tools: 'Ferramentas', exploreMarketplace: 'Explorar Mercado', + appDetail: 'Detalhes do aplicativo', + account: 'Conta', }, userProfile: { settings: 'Configurações', @@ -644,6 +646,7 @@ const translation = { license: { expiring: 'Expirando em um dia', expiring_plural: 'Expirando em {{count}} dias', + unlimited: 'Ilimitado', }, pagination: { perPage: 'Itens por página', @@ -667,6 +670,7 @@ const translation = { supportedFormats: 'Suporta PNG, JPG, JPEG, WEBP e GIF', browse: 'navegar', }, + you: 'Você', } export default translation diff --git a/web/i18n/pt-BR/login.ts b/web/i18n/pt-BR/login.ts index 7af5181bb9..0880b4776e 100644 --- a/web/i18n/pt-BR/login.ts +++ b/web/i18n/pt-BR/login.ts @@ -105,6 +105,11 @@ const translation = { licenseLost: 'Licença perdida', licenseInactive: 'Licença inativa', licenseExpiredTip: 'A licença do Dify Enterprise para seu espaço de trabalho expirou. Entre em contato com o administrador para continuar usando o Dify.', + webapp: { + noLoginMethod: 'Método de autenticação não configurado para o aplicativo web', + disabled: 'A autenticação do aplicativo da web está desativada. Por favor, entre em contato com o administrador do sistema para habilitá-la. Você pode tentar usar o aplicativo diretamente.', + noLoginMethodTip: 'Por favor, entre em contato com o administrador do sistema para adicionar um método de autenticação.', + }, } export default translation diff --git a/web/i18n/pt-BR/plugin.ts b/web/i18n/pt-BR/plugin.ts index c02f9cb7e3..8eb44f83d6 100644 --- a/web/i18n/pt-BR/plugin.ts +++ b/web/i18n/pt-BR/plugin.ts @@ -62,6 +62,7 @@ const translation = { descriptionPlaceholder: 'Breve descrição da finalidade da ferramenta, por exemplo, obter a temperatura para um local específico.', uninstalledTitle: 'Ferramenta não instalada', unsupportedTitle: 'Ação sem suporte', + toolSetting: 'Configurações da Ferramenta', }, serviceOk: 'Serviço OK', endpointsTip: 'Este plug-in fornece funcionalidades específicas por meio de endpoints e você pode configurar vários conjuntos de endpoints para o workspace atual.', @@ -210,6 +211,7 @@ const translation = { title: 'Plugins', }, difyVersionNotCompatible: 'A versão atual do Dify não é compatível com este plugin, por favor atualize para a versão mínima exigida: {{minimalDifyVersion}}', + requestAPlugin: 'Solicitar um plugin', } export default translation diff --git a/web/i18n/pt-BR/workflow.ts b/web/i18n/pt-BR/workflow.ts index 7724dfcf6a..11ee0ed9a1 100644 --- a/web/i18n/pt-BR/workflow.ts +++ b/web/i18n/pt-BR/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: 'JSON gerado por ferramenta', }, + authorize: 'Autorizar', }, questionClassifiers: { model: 'modelo', diff --git a/web/i18n/ro-RO/app.ts b/web/i18n/ro-RO/app.ts index a96c94d02f..adf82aa38e 100644 --- a/web/i18n/ro-RO/app.ts +++ b/web/i18n/ro-RO/app.ts @@ -209,6 +209,41 @@ const translation = { configure: 'Configurează', modelNotSupportedTip: 'Modelul actual nu suportă această funcție și este downgradat automat la injecția de prompt.', }, + accessItemsDescription: { + specific: 'Numai grupuri sau membri specifici pot accesa aplicația web.', + organization: 'Oricine din organizație poate accesa aplicația web', + anyone: 'Oricine poate accesa aplicația web', + }, + accessControlDialog: { + accessItems: { + anyone: 'Oricine are linkul', + specific: 'Grupuri sau membri specifici', + organization: 'Numai membrii din cadrul întreprinderii', + }, + operateGroupAndMember: { + searchPlaceholder: 'Caută grupuri și membri', + allMembers: 'Toți membrii', + expand: 'Expandează', + noResult: 'Niciun rezultat', + }, + title: 'Controlul Accesului la Aplicația Web', + description: 'Setați permisiunile de acces la aplicația web', + accessLabel: 'Cine are acces', + groups_one: '{{count}} GRUP', + groups_other: '{{count}} GRUPURI', + members_one: '{{count}} MEMBRU', + members_other: '{{count}} MEMBRI', + noGroupsOrMembers: 'Niciun grup sau membri selectați', + webAppSSONotEnabledTip: 'Vă rugăm să contactați administratorul de întreprindere pentru a configura metoda de autentificare a aplicației web.', + updateSuccess: 'Actualizare reușită', + }, + publishApp: { + title: 'Cine poate accesa aplicația web', + notSet: 'Nu este setat', + notSetDesc: 'În prezent, nimeni nu poate accesa aplicația web. Vă rugăm să setați permisiunile.', + }, + accessControl: 'Controlul Accesului la Aplicația Web', + noAccessPermission: 'Nici o permisiune pentru a accesa aplicația web', } export default translation diff --git a/web/i18n/ro-RO/common.ts b/web/i18n/ro-RO/common.ts index 1d3c1023ab..f736240a78 100644 --- a/web/i18n/ro-RO/common.ts +++ b/web/i18n/ro-RO/common.ts @@ -145,6 +145,8 @@ const translation = { newDataset: 'Creează Cunoștințe', tools: 'Instrumente', exploreMarketplace: 'Explorați Marketplace', + appDetail: 'Detalii aplicație', + account: 'Cont', }, userProfile: { settings: 'Setări', @@ -644,6 +646,7 @@ const translation = { license: { expiring: 'Expiră într-o zi', expiring_plural: 'Expiră în {{count}} zile', + unlimited: 'Nelimitat', }, pagination: { perPage: 'Articole pe pagină', @@ -667,6 +670,7 @@ const translation = { browse: 'naviga', dropImageHere: 'Trageți imaginea aici sau', }, + you: 'Tu', } export default translation diff --git a/web/i18n/ro-RO/login.ts b/web/i18n/ro-RO/login.ts index 12878d46c0..6a6a6edc64 100644 --- a/web/i18n/ro-RO/login.ts +++ b/web/i18n/ro-RO/login.ts @@ -105,6 +105,11 @@ const translation = { licenseExpired: 'Licență expirată', licenseLost: 'Licență pierdută', licenseExpiredTip: 'Licența Dify Enterprise pentru spațiul de lucru a expirat. Contactați administratorul pentru a continua să utilizați Dify.', + webapp: { + noLoginMethod: 'Metoda de autentificare nu este configurată pentru aplicația web', + noLoginMethodTip: 'Vă rugăm să contactați administratorul sistemului pentru a adăuga o metodă de autentificare.', + disabled: 'Autentificarea webapp-ului este dezactivată. Vă rugăm să contactați administratorul sistemului pentru a o activa. Puteți încerca să folosiți aplicația direct.', + }, } export default translation diff --git a/web/i18n/ro-RO/plugin.ts b/web/i18n/ro-RO/plugin.ts index 4fe0782496..11dc6b8f59 100644 --- a/web/i18n/ro-RO/plugin.ts +++ b/web/i18n/ro-RO/plugin.ts @@ -62,6 +62,7 @@ const translation = { descriptionPlaceholder: 'Scurtă descriere a scopului instrumentului, de exemplu, obțineți temperatura pentru o anumită locație.', toolLabel: 'Unealtă', uninstalledTitle: 'Instrumentul nu este instalat', + toolSetting: 'Setările instrumentului', }, endpointDeleteContent: 'Doriți să eliminați {{name}}?', strategyNum: '{{num}} {{strategie}} INCLUS', @@ -210,6 +211,7 @@ const translation = { title: 'Pluginuri', }, difyVersionNotCompatible: 'Versiunea curentă Dify nu este compatibilă cu acest plugin, vă rugăm să faceți upgrade la versiunea minimă necesară: {{minimalDifyVersion}}', + requestAPlugin: 'Solicitați un plugin', } export default translation diff --git a/web/i18n/ro-RO/workflow.ts b/web/i18n/ro-RO/workflow.ts index a93b7fcd14..fabea57556 100644 --- a/web/i18n/ro-RO/workflow.ts +++ b/web/i18n/ro-RO/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: 'JSON generat de instrument', }, + authorize: 'Autorizați', }, questionClassifiers: { model: 'model', diff --git a/web/i18n/ru-RU/app.ts b/web/i18n/ru-RU/app.ts index 609b891c5c..fa73e33197 100644 --- a/web/i18n/ru-RU/app.ts +++ b/web/i18n/ru-RU/app.ts @@ -209,6 +209,41 @@ const translation = { modelNotSupportedTip: 'Текущая модель не поддерживает эту функцию и автоматически понижается до инъекции подсказок.', structuredTip: 'Структурированные выходные данные — это функция, которая гарантирует, что модель всегда будет генерировать ответы, соответствующие вашей предоставленной JSON-схеме.', }, + accessItemsDescription: { + anyone: 'Любой может получить доступ к веб-приложению', + specific: 'Только определенные группы или участники могут получить доступ к веб-приложению.', + organization: 'Любой в организации может получить доступ к веб-приложению', + }, + accessControlDialog: { + accessItems: { + anyone: 'Кто угодно с ссылкой', + specific: 'Конкретные группы или члены', + organization: 'Только члены внутри предприятия', + }, + operateGroupAndMember: { + searchPlaceholder: 'Искать группы и участников', + expand: 'Расширить', + noResult: 'Нет результата', + allMembers: 'Все члены', + }, + title: 'Управление доступом к веб-приложению', + description: 'Установите разрешения на доступ к веб-приложению', + accessLabel: 'Кто имеет доступ', + groups_one: '{{count}} ГРУППА', + groups_other: '{{count}} ГРУПП', + members_one: '{{count}} УЧАСТНИК', + members_other: '{{count}} УЧАСТНИКИ', + noGroupsOrMembers: 'Группы или участники не выбраны', + updateSuccess: 'Обновление прошло успешно', + webAppSSONotEnabledTip: 'Пожалуйста, свяжитесь с администратором предприятия, чтобы настроить метод аутентификации веб-приложения.', + }, + publishApp: { + title: 'Кто может получить доступ к веб-приложению', + notSet: 'Не установлено', + notSetDesc: 'В настоящее время никто не может получить доступ к веб-приложению. Пожалуйста, установите права доступа.', + }, + accessControl: 'Управление доступом к веб-приложению', + noAccessPermission: 'Нет разрешения на доступ к веб-приложению', } export default translation diff --git a/web/i18n/ru-RU/common.ts b/web/i18n/ru-RU/common.ts index 1c7b41169b..37d207d357 100644 --- a/web/i18n/ru-RU/common.ts +++ b/web/i18n/ru-RU/common.ts @@ -149,6 +149,8 @@ const translation = { newDataset: 'Создать знания', tools: 'Инструменты', exploreMarketplace: 'Подробнее о Marketplace', + appDetail: 'Детали приложения', + account: 'Учетная запись', }, userProfile: { settings: 'Настройки', @@ -644,6 +646,7 @@ const translation = { license: { expiring: 'Срок действия истекает за один день', expiring_plural: 'Срок действия истекает через {{count}} дней', + unlimited: 'Неограниченный', }, pagination: { perPage: 'Элементов на странице', @@ -667,6 +670,7 @@ const translation = { dropImageHere: 'Перетащите ваше изображение сюда или', supportedFormats: 'Поддерживает PNG, JPG, JPEG, WEBP и GIF', }, + you: 'Ты', } export default translation diff --git a/web/i18n/ru-RU/login.ts b/web/i18n/ru-RU/login.ts index 5c46cb7ff9..9c623fe5b6 100644 --- a/web/i18n/ru-RU/login.ts +++ b/web/i18n/ru-RU/login.ts @@ -105,6 +105,11 @@ const translation = { licenseLost: 'Утеряна лицензия', licenseInactiveTip: 'Лицензия Dify Enterprise для рабочего пространства неактивна. Обратитесь к своему администратору, чтобы продолжить использование Dify.', licenseExpiredTip: 'Срок действия лицензии Dify Enterprise для рабочего пространства истек. Обратитесь к своему администратору, чтобы продолжить использование Dify.', + webapp: { + noLoginMethod: 'Метод аутентификации не настроен для веб-приложения', + noLoginMethodTip: 'Пожалуйста, свяжитесь с администратором системы, чтобы добавить метод аутентификации.', + disabled: 'Аутентификация веб-приложения отключена. Пожалуйста, свяжитесь с администратором системы, чтобы включить ее. Вы можете попробовать использовать приложение напрямую.', + }, } export default translation diff --git a/web/i18n/ru-RU/plugin.ts b/web/i18n/ru-RU/plugin.ts index 9d99bc11d9..3dc48a0327 100644 --- a/web/i18n/ru-RU/plugin.ts +++ b/web/i18n/ru-RU/plugin.ts @@ -62,6 +62,7 @@ const translation = { params: 'КОНФИГУРАЦИЯ РАССУЖДЕНИЙ', unsupportedContent2: 'Нажмите, чтобы переключить версию.', uninstalledLink: 'Управление в плагинах', + toolSetting: 'Настройки инструмента', }, configureTool: 'Инструмент настройки', endpointsTip: 'Этот плагин предоставляет определенные функциональные возможности через конечные точки, и вы можете настроить несколько наборов конечных точек для текущей рабочей области.', @@ -210,6 +211,7 @@ const translation = { title: 'Плагины', }, difyVersionNotCompatible: 'Текущая версия Dify не совместима с этим плагином, пожалуйста, обновите до минимально необходимой версии: {{minimalDifyVersion}}', + requestAPlugin: 'Запросите плагин', } export default translation diff --git a/web/i18n/ru-RU/workflow.ts b/web/i18n/ru-RU/workflow.ts index e170e64b83..7b22876f5a 100644 --- a/web/i18n/ru-RU/workflow.ts +++ b/web/i18n/ru-RU/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: 'json, сгенерированный инструментом', }, + authorize: 'Авторизовать', }, questionClassifiers: { model: 'модель', diff --git a/web/i18n/sl-SI/app.ts b/web/i18n/sl-SI/app.ts index f988114acd..6241d40f30 100644 --- a/web/i18n/sl-SI/app.ts +++ b/web/i18n/sl-SI/app.ts @@ -209,6 +209,41 @@ const translation = { modelNotSupportedTip: 'Trenutni model ne podpira te funkcije in se samodejno zniža na vbrizgavanje pozivov.', structuredTip: 'Strukturirani izhodi so funkcija, ki zagotavlja, da bo model vedno generiral odgovore, ki se držijo vašega posredovanega JSON sheme.', }, + accessItemsDescription: { + anyone: 'Vsakdo lahko dostopa do spletne aplikacije', + specific: 'Samo določenim skupinam ali članom je omogočen dostop do spletne aplikacije', + organization: 'Vsakdo v organizaciji lahko dostopa do spletne aplikacije', + }, + accessControlDialog: { + accessItems: { + anyone: 'Kdorkoli s povezavo', + specific: 'Specifične skupine ali člani', + organization: 'Samo člani znotraj podjetja', + }, + operateGroupAndMember: { + searchPlaceholder: 'Išči skupine in člane', + allMembers: 'Vsi člani', + expand: 'Razširi', + noResult: 'Brez rezultata', + }, + title: 'Nadzor dostopa do spletne aplikacije', + description: 'Nastavite dovoljenja za dostop do spletne aplikacije', + accessLabel: 'Kdo ima dostop', + groups_one: '{{count}} SKUPINA', + groups_other: '{{count}} SKUPIN', + members_one: '{{count}} ČLAN', + members_other: '{{count}} ČLANOV', + updateSuccess: 'Posodobitev uspešna', + noGroupsOrMembers: 'Nobene skupine ali članov ni izbranih', + webAppSSONotEnabledTip: 'Prosimo, da se obrnete na skrbnika podjetja, da konfigurira način avtentikacije spletne aplikacije.', + }, + publishApp: { + title: 'Kdo lahko dostopa do spletne aplikacije', + notSet: 'Ni nastavljeno', + notSetDesc: 'Trenutno nihče ne more dostopati do spletne aplikacije. Prosimo, nastavite dovoljenja.', + }, + accessControl: 'Nadzor dostopa do spletne aplikacije', + noAccessPermission: 'Brez dovoljenja za dostop do spletne aplikacije', } export default translation diff --git a/web/i18n/sl-SI/common.ts b/web/i18n/sl-SI/common.ts index d4b78d41e5..b43a2dbbb2 100644 --- a/web/i18n/sl-SI/common.ts +++ b/web/i18n/sl-SI/common.ts @@ -149,6 +149,8 @@ const translation = { newDataset: 'Ustvari znanje', tools: 'Orodja', exploreMarketplace: 'Raziščite Marketplace', + appDetail: 'Podrobnosti o aplikaciji', + account: 'Račun', }, userProfile: { settings: 'Nastavitve', @@ -843,6 +845,7 @@ const translation = { license: { expiring_plural: 'Poteče v {{count}} dneh', expiring: 'Poteče v enem dnevu', + unlimited: 'Brez omejitev', }, pagination: { perPage: 'Elementi na stran', @@ -866,6 +869,7 @@ const translation = { browse: 'brskati', dropImageHere: 'Tukaj spustite svojo sliko ali', }, + you: 'Ti', } export default translation diff --git a/web/i18n/sl-SI/login.ts b/web/i18n/sl-SI/login.ts index 70350021bc..12b424b0d7 100644 --- a/web/i18n/sl-SI/login.ts +++ b/web/i18n/sl-SI/login.ts @@ -105,6 +105,11 @@ const translation = { withSSO: 'Nadaljujte z enotno prijavo', licenseLostTip: 'Povezava z licenčnim strežnikom Dify ni uspela. Če želite še naprej uporabljati Dify, se obrnite na skrbnika.', licenseInactiveTip: 'Licenca Dify Enterprise za vaš delovni prostor je neaktivna. Če želite še naprej uporabljati Dify, se obrnite na skrbnika.', + webapp: { + noLoginMethod: 'Metoda overjanja ni nastavljena za spletno aplikacijo', + noLoginMethodTip: 'Prosimo, da se obrnete na sistemskega skrbnika, da dodate metodo za avtentikacijo.', + disabled: 'Avtentikacija v spletni aplikaciji je onemogočena. Prosimo, kontaktirajte skrbnika sistema, da jo omogoči. Poskusite lahko neposredno uporabljati aplikacijo.', + }, } export default translation diff --git a/web/i18n/sl-SI/plugin.ts b/web/i18n/sl-SI/plugin.ts index 848ef39170..5580d4b1f4 100644 --- a/web/i18n/sl-SI/plugin.ts +++ b/web/i18n/sl-SI/plugin.ts @@ -65,6 +65,7 @@ const translation = { empty: 'Kliknite gumb \' \' za dodajanje orodij. Dodate lahko več orodij.', paramsTip1: 'Nadzoruje parametre sklepanja LLM.', paramsTip2: 'Ko je \'Avtomatsko\' izklopljeno, se uporablja privzeta vrednost.', + toolSetting: 'Nastavitve orodja', }, endpointDisableContent: 'Ali želite onemogočiti {{name}}?', serviceOk: 'Storitve so v redu', @@ -210,6 +211,7 @@ const translation = { allCategories: 'Vse kategorije', submitPlugin: 'Oddajte vtičnik', difyVersionNotCompatible: 'Trenutna različica Dify ni združljiva s to vtičnico, prosimo, posodobite na minimalno zahtevano različico: {{minimalDifyVersion}}', + requestAPlugin: 'Zahtevajte vtičnik', } export default translation diff --git a/web/i18n/sl-SI/workflow.ts b/web/i18n/sl-SI/workflow.ts index 1aa639222e..a0f4f8d95e 100644 --- a/web/i18n/sl-SI/workflow.ts +++ b/web/i18n/sl-SI/workflow.ts @@ -1096,6 +1096,7 @@ const translation = { }, inputVars: 'Vhodne spremenljivke', toAuthorize: 'Za odobritev', + authorize: 'Pooblasti', }, questionClassifiers: { outputVars: { diff --git a/web/i18n/th-TH/app.ts b/web/i18n/th-TH/app.ts index f4999e9aff..9204c71d32 100644 --- a/web/i18n/th-TH/app.ts +++ b/web/i18n/th-TH/app.ts @@ -205,6 +205,41 @@ const translation = { modelNotSupported: 'โมเดลไม่ได้รับการสนับสนุน', modelNotSupportedTip: 'โมเดลปัจจุบันไม่รองรับฟีเจอร์นี้และจะถูกลดระดับเป็นการฉีดคำสั่งโดยอัตโนมัติ.', }, + accessItemsDescription: { + anyone: 'ใครก็สามารถเข้าถึงเว็บแอปได้', + specific: 'สมาชิกหรือกลุ่มเฉพาะเท่านั้นที่สามารถเข้าถึงแอปเว็บได้', + organization: 'ใครก็ได้ในองค์กรสามารถเข้าถึงแอปเว็บได้', + }, + accessControlDialog: { + accessItems: { + specific: 'กลุ่มหรือสมาชิกเฉพาะ', + organization: 'เฉพาะสมาชิกภายในองค์กร', + anyone: 'ใครก็ตามที่มีลิงก์', + }, + operateGroupAndMember: { + searchPlaceholder: 'ค้นหากลุ่มและสมาชิก', + allMembers: 'สมาชิกทั้งหมด', + noResult: 'ไม่มีผลลัพธ์', + expand: 'ขยาย', + }, + title: 'การควบคุมการเข้าถึงเว็บแอปพลิเคชัน', + description: 'ตั้งค่าสิทธิ์การเข้าถึงเว็บแอป', + accessLabel: 'ใครมีสิทธิ์เข้าถึง', + groups_one: '{{count}} กลุ่ม', + groups_other: '{{count}} กลุ่ม', + members_one: '{{count}} สมาชิก', + noGroupsOrMembers: 'ไม่มีกลุ่มหรือสมาชิกที่เลือก', + webAppSSONotEnabledTip: 'กรุณาติดต่อผู้ดูแลระบบองค์กรเพื่อกำหนดวิธีการตรวจสอบสิทธิ์แอปเว็บ.', + updateSuccess: 'อัปเดตสำเร็จแล้ว', + members_other: '{{count}} สมาชิก', + }, + publishApp: { + title: 'ใครสามารถเข้าถึงแอปเว็บได้', + notSet: 'ยังไม่ได้ตั้งค่า', + notSetDesc: 'ขณะนี้ไม่มีใครสามารถเข้าถึงแอปเว็บได้ กรุณาเพิ่มสิทธิ์การเข้าถึง.', + }, + accessControl: 'การควบคุมการเข้าถึงเว็บแอปพลิเคชัน', + noAccessPermission: 'ไม่มีสิทธิ์เข้าถึงเว็บแอป', } export default translation diff --git a/web/i18n/th-TH/common.ts b/web/i18n/th-TH/common.ts index 9b72257a1f..7425a178d3 100644 --- a/web/i18n/th-TH/common.ts +++ b/web/i18n/th-TH/common.ts @@ -144,6 +144,8 @@ const translation = { newDataset: 'สร้างความรู้', tools: 'เครื่อง มือ', exploreMarketplace: 'สํารวจ Marketplace', + appDetail: 'รายละเอียดแอป', + account: 'บัญชี', }, userProfile: { settings: 'การตั้งค่า', @@ -639,6 +641,7 @@ const translation = { license: { expiring: 'หมดอายุในหนึ่งวัน', expiring_plural: 'หมดอายุใน {{count}} วัน', + unlimited: 'ไม่มีขีดจำกัด', }, pagination: { perPage: 'รายการต่อหน้า', @@ -662,6 +665,7 @@ const translation = { browse: 'ท่องเว็บ', supportedFormats: 'รองรับ PNG, JPG, JPEG, WEBP และ GIF', }, + you: 'คุณ', } export default translation diff --git a/web/i18n/th-TH/login.ts b/web/i18n/th-TH/login.ts index 75f569d3a2..da24be7ea5 100644 --- a/web/i18n/th-TH/login.ts +++ b/web/i18n/th-TH/login.ts @@ -104,6 +104,11 @@ const translation = { licenseLostTip: 'เชื่อมต่อเซิร์ฟเวอร์ใบอนุญาต Dify ไม่สําเร็จ โปรดติดต่อผู้ดูแลระบบของคุณเพื่อใช้ Dify ต่อไป', licenseInactive: 'ใบอนุญาตไม่ใช้งาน', licenseInactiveTip: 'สิทธิ์การใช้งาน Dify Enterprise สําหรับพื้นที่ทํางานของคุณไม่ได้ใช้งาน โปรดติดต่อผู้ดูแลระบบของคุณเพื่อใช้ Dify ต่อไป', + webapp: { + noLoginMethodTip: 'กรุณาติดต่อผู้ดูแลระบบเพื่อเพิ่มวิธีการตรวจสอบสิทธิ์.', + noLoginMethod: 'ไม่ได้กำหนดวิธีการตรวจสอบสิทธิ์สำหรับเว็บแอป', + disabled: 'การรับรองความถูกต้องของเว็บแอปถูกปิดใช้งาน โปรดติดต่อผู้ดูแลระบบเพื่อเปิดใช้งาน คุณสามารถลองใช้แอปโดยตรงได้', + }, } export default translation diff --git a/web/i18n/th-TH/plugin.ts b/web/i18n/th-TH/plugin.ts index eb42371fbe..de7ed8c84e 100644 --- a/web/i18n/th-TH/plugin.ts +++ b/web/i18n/th-TH/plugin.ts @@ -62,6 +62,7 @@ const translation = { uninstalledTitle: 'ไม่ได้ติดตั้งเครื่องมือ', descriptionPlaceholder: 'คําอธิบายสั้น ๆ เกี่ยวกับวัตถุประสงค์ของเครื่องมือ เช่น รับอุณหภูมิสําหรับตําแหน่งเฉพาะ', uninstalledContent: 'ปลั๊กอินนี้ติดตั้งจากที่เก็บในเครื่อง/GitHub กรุณาใช้หลังการติดตั้ง', + toolSetting: 'การตั้งค่าเครื่องมือ', }, endpointDisableContent: 'คุณต้องการปิดการใช้งาน {{name}} หรือไม่?', configureApp: 'กําหนดค่าแอป', @@ -210,6 +211,7 @@ const translation = { title: 'ปลั๊กอิน', }, difyVersionNotCompatible: 'เวอร์ชั่นปัจจุบันของ Dify ไม่สามารถใช้งานร่วมกับปลั๊กอินนี้ได้ กรุณาอัปเกรดไปยังเวอร์ชั่นขั้นต่ำที่ต้องการ: {{minimalDifyVersion}}', + requestAPlugin: 'ขอปลั๊กอิน', } export default translation diff --git a/web/i18n/th-TH/workflow.ts b/web/i18n/th-TH/workflow.ts index d1f9084c81..cc2cee418f 100644 --- a/web/i18n/th-TH/workflow.ts +++ b/web/i18n/th-TH/workflow.ts @@ -659,6 +659,7 @@ const translation = { }, json: 'เครื่องมือสร้าง JSON', }, + authorize: 'อนุญาต', }, questionClassifiers: { model: 'แบบ', diff --git a/web/i18n/tr-TR/app.ts b/web/i18n/tr-TR/app.ts index 0dbc52bf36..995cc9c795 100644 --- a/web/i18n/tr-TR/app.ts +++ b/web/i18n/tr-TR/app.ts @@ -205,6 +205,41 @@ const translation = { modelNotSupportedTip: 'Mevcut model bu özelliği desteklemiyor ve otomatik olarak prompt enjeksiyonuna düşürülüyor.', structuredTip: 'Yapılandırılmış Çıktılar, modelin sağladığınız JSON Şemasına uyacak şekilde her zaman yanıtlar üretmesini sağlayan bir özelliktir.', }, + accessItemsDescription: { + anyone: 'Herkes web uygulamasına erişebilir', + organization: 'Kuruluşta herkes web uygulamasına erişebilir.', + specific: 'Sadece belirli gruplar veya üyeler web uygulamasına erişebilir.', + }, + accessControlDialog: { + accessItems: { + anyone: 'Bağlantıya sahip olan herkes', + organization: 'Sadece işletme içindeki üyeler', + specific: 'Belirli gruplar veya üyeler', + }, + operateGroupAndMember: { + searchPlaceholder: 'Grupları ve üyeleri ara', + expand: 'Genişlet', + allMembers: 'Tüm üyeler', + noResult: 'Sonuç yok', + }, + title: 'Web Uygulaması Erişim Kontrolü', + description: 'Web uygulaması erişim izinlerini ayarlayın', + accessLabel: 'Kimin erişimi var', + groups_other: '{{count}} GRUP', + members_one: '{{count}} ÜYE', + members_other: '{{count}} ÜYE', + noGroupsOrMembers: 'Seçilen grup veya üye yok', + webAppSSONotEnabledTip: 'Lütfen web uygulaması kimlik doğrulama yöntemini yapılandırmak için kurumsal yöneticinizle iletişime geçin.', + updateSuccess: 'Başarıyla güncellendi', + groups_one: '{{count}} GRUP', + }, + publishApp: { + title: 'Web uygulamasına kim erişebilir', + notSet: 'Ayar yapılmamış', + notSetDesc: 'Şu anda kimse web uygulamasına erişemiyor. Lütfen izinleri ayarlayın.', + }, + accessControl: 'Web Uygulaması Erişim Kontrolü', + noAccessPermission: 'Web uygulamasına erişim izni yok', } export default translation diff --git a/web/i18n/tr-TR/common.ts b/web/i18n/tr-TR/common.ts index 42c0dca72b..62ce150986 100644 --- a/web/i18n/tr-TR/common.ts +++ b/web/i18n/tr-TR/common.ts @@ -149,6 +149,8 @@ const translation = { newDataset: 'Bilgi Oluştur', tools: 'Araçlar', exploreMarketplace: 'Marketplace\'i Keşfedin', + appDetail: 'Uygulama Detayı', + account: 'Hesap', }, userProfile: { settings: 'Ayarlar', @@ -644,6 +646,7 @@ const translation = { license: { expiring_plural: '{{count}} gün içinde sona eriyor', expiring: 'Bir günde sona eriyor', + unlimited: 'Sınırsız', }, pagination: { perPage: 'Sayfa başına öğe sayısı', @@ -667,6 +670,7 @@ const translation = { dropImageHere: 'Görüntünüzü buraya bırakın veya', browse: 'tarayıcı', }, + you: 'Sen', } export default translation diff --git a/web/i18n/tr-TR/login.ts b/web/i18n/tr-TR/login.ts index e742548dc5..e6471d935f 100644 --- a/web/i18n/tr-TR/login.ts +++ b/web/i18n/tr-TR/login.ts @@ -105,6 +105,11 @@ const translation = { licenseExpired: 'Lisansın Süresi Doldu', licenseLost: 'Lisans Kaybedildi', licenseInactive: 'Lisans Etkin Değil', + webapp: { + disabled: 'Web uygulaması kimlik doğrulaması devre dışı. Lütfen bu özelliği etkinleştirmesi için sistem yöneticisi ile iletişime geçin. Uygulamayı doğrudan kullanmayı deneyebilirsiniz.', + noLoginMethod: 'Web uygulaması için kimlik doğrulama yöntemi yapılandırılmamış', + noLoginMethodTip: 'Lütfen bir kimlik doğrulama yöntemi eklemek için sistem yöneticisi ile iletişime geçin.', + }, } export default translation diff --git a/web/i18n/tr-TR/plugin.ts b/web/i18n/tr-TR/plugin.ts index c434052081..aef546589c 100644 --- a/web/i18n/tr-TR/plugin.ts +++ b/web/i18n/tr-TR/plugin.ts @@ -62,6 +62,7 @@ const translation = { params: 'AKIL YÜRÜTME YAPILANDIRMASI', paramsTip2: '\'Otomatik\' kapalıyken, varsayılan değer kullanılır.', unsupportedTitle: 'Desteklenmeyen Eylem', + toolSetting: 'Araç Ayarları', }, strategyNum: '{{sayı}} {{strateji}} DAHİL', switchVersion: 'Sürümü Değiştir', @@ -210,6 +211,7 @@ const translation = { title: 'Eklentiler', }, difyVersionNotCompatible: 'Mevcut Dify sürümü bu eklentiyle uyumlu değil, lütfen gerekli minimum sürüme güncelleyin: {{minimalDifyVersion}}', + requestAPlugin: 'Bir eklenti iste', } export default translation diff --git a/web/i18n/tr-TR/workflow.ts b/web/i18n/tr-TR/workflow.ts index 36bd101cbf..1358bbf645 100644 --- a/web/i18n/tr-TR/workflow.ts +++ b/web/i18n/tr-TR/workflow.ts @@ -661,6 +661,7 @@ const translation = { }, json: 'araç tarafından oluşturulan json', }, + authorize: 'Yetkilendirmek', }, questionClassifiers: { model: 'model', diff --git a/web/i18n/uk-UA/app.ts b/web/i18n/uk-UA/app.ts index a3834aa32b..4bbb0dcbf1 100644 --- a/web/i18n/uk-UA/app.ts +++ b/web/i18n/uk-UA/app.ts @@ -209,6 +209,41 @@ const translation = { modelNotSupportedTip: 'Поточна модель не підтримує цю функцію та автоматично знижується до ін\'єкції запитів.', structuredTip: 'Структуровані виходи - це функція, яка забезпечує, що модель завжди генеруватиме відповіді, що відповідають наданій вами схемі JSON.', }, + accessItemsDescription: { + anyone: 'Будь-хто може отримати доступ до веб-додатку', + specific: 'Тільки окремі групи або члени можуть отримати доступ до веб-додатку.', + organization: 'Будь-хто в організації може отримати доступ до веб-додатку.', + }, + accessControlDialog: { + accessItems: { + anyone: 'Кожен, у кого є посилання', + specific: 'Конкретні групи або члени', + organization: 'Тільки члени підприємства', + }, + operateGroupAndMember: { + searchPlaceholder: 'Шукати групи та учасників', + allMembers: 'Всі члени', + expand: 'розвивати', + noResult: 'Немає результату', + }, + title: 'Контроль доступу до веб-додатка', + description: 'Встановіть дозволи доступу до веб-додатку', + accessLabel: 'Хто має доступ', + groups_one: '{{count}} ГРУПА', + groups_other: '{{count}} ГРУП', + members_one: '{{count}} ЧЛЕН', + members_other: '{{count}} ЧЛЕНІ', + noGroupsOrMembers: 'Не вибрано групи чи учасників', + updateSuccess: 'Оновлення успішно', + webAppSSONotEnabledTip: 'Будь ласка, зв\'яжіться з адміністратором підприємства для налаштування методу аутентифікації веб-додатку.', + }, + publishApp: { + title: 'Хто може отримати доступ до веб-додатку', + notSet: 'Не встановлено', + notSetDesc: 'На даний момент ніхто не може отримати доступ до веб-додатку. Будь ласка, налаштуйте дозволи.', + }, + accessControl: 'Контроль доступу до веб-додатків', + noAccessPermission: 'Немає дозволу на доступ до веб-додатку', } export default translation diff --git a/web/i18n/uk-UA/common.ts b/web/i18n/uk-UA/common.ts index dee558ad44..a80e308b78 100644 --- a/web/i18n/uk-UA/common.ts +++ b/web/i18n/uk-UA/common.ts @@ -145,6 +145,8 @@ const translation = { newDataset: 'Створити знання', tools: 'Інструменти', exploreMarketplace: 'Дізнайтеся більше про Marketplace', + appDetail: 'Деталі програми', + account: 'Обліковий запис', }, userProfile: { settings: 'Налаштування', @@ -645,6 +647,7 @@ const translation = { license: { expiring: 'Термін дії закінчується за один день', expiring_plural: 'Термін дії закінчується за {{count}} днів', + unlimited: 'Безмежний', }, pagination: { perPage: 'Елементів на сторінці', @@ -668,6 +671,7 @@ const translation = { supportedFormats: 'Підтримує PNG, JPG, JPEG, WEBP і GIF', dropImageHere: 'Перетягніть зображення сюди або', }, + you: 'Ти', } export default translation diff --git a/web/i18n/uk-UA/login.ts b/web/i18n/uk-UA/login.ts index e6d1d15dd5..13c71c32c0 100644 --- a/web/i18n/uk-UA/login.ts +++ b/web/i18n/uk-UA/login.ts @@ -105,6 +105,11 @@ const translation = { licenseLost: 'Ліцензію втрачено', licenseInactiveTip: 'Ліцензія Dify Enterprise для вашої робочої області неактивна. Будь ласка, зверніться до свого адміністратора, щоб продовжити користуватися Dify.', licenseExpiredTip: 'Термін дії ліцензії Dify Enterprise для вашого робочого простору закінчився. Будь ласка, зверніться до свого адміністратора, щоб продовжити користуватися Dify.', + webapp: { + noLoginMethod: 'Метод аутентифікації не налаштований для веб-додатку', + noLoginMethodTip: 'Будь ласка, зв\'яжіться з адміністратором системи, щоб додати метод автентифікації.', + disabled: 'Аутентифікацію вебдодатка вимкнено. Будь ласка, зв\'яжіться з адміністратором системи, щоб увімкнути її. Ви можете спробувати використовувати додаток безпосередньо.', + }, } export default translation diff --git a/web/i18n/uk-UA/plugin.ts b/web/i18n/uk-UA/plugin.ts index 465624f2d3..ebc3d927d3 100644 --- a/web/i18n/uk-UA/plugin.ts +++ b/web/i18n/uk-UA/plugin.ts @@ -62,6 +62,7 @@ const translation = { auto: 'Автоматичний', uninstalledContent: 'Цей плагін встановлюється з локального/GitHub репозиторію. Будь ласка, використовуйте після встановлення.', unsupportedContent: 'Встановлена версія плагіна не передбачає цієї дії.', + toolSetting: 'Налаштування інструментів', }, modelNum: '{{num}} МОДЕЛІ В КОМПЛЕКТІ', switchVersion: 'Версія перемикача', @@ -210,6 +211,7 @@ const translation = { title: 'Плагіни', }, difyVersionNotCompatible: 'Поточна версія Dify не сумісна з цим плагіном, будь ласка, оновіть до мінімальної версії: {{minimalDifyVersion}}', + requestAPlugin: 'Запросити плагін', } export default translation diff --git a/web/i18n/uk-UA/workflow.ts b/web/i18n/uk-UA/workflow.ts index ff6a75242f..bbe32c22c7 100644 --- a/web/i18n/uk-UA/workflow.ts +++ b/web/i18n/uk-UA/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: 'JSON, згенерований інструментом', }, + authorize: 'Уповноважити', }, questionClassifiers: { model: 'модель', diff --git a/web/i18n/vi-VN/app.ts b/web/i18n/vi-VN/app.ts index c01c00c45c..243454d011 100644 --- a/web/i18n/vi-VN/app.ts +++ b/web/i18n/vi-VN/app.ts @@ -209,6 +209,41 @@ const translation = { modelNotSupportedTip: 'Mô hình hiện tại không hỗ trợ tính năng này và tự động bị hạ cấp xuống việc tiêm lệnh.', moreFillTip: 'Hiển thị tối đa 10 cấp độ lồng ghép', }, + accessItemsDescription: { + anyone: 'Mọi người đều có thể truy cập ứng dụng web.', + specific: 'Chỉ những nhóm hoặc thành viên cụ thể mới có thể truy cập ứng dụng web.', + organization: 'Bất kỳ ai trong tổ chức đều có thể truy cập ứng dụng web.', + }, + accessControlDialog: { + accessItems: { + anyone: 'Ai có liên kết', + specific: 'Các nhóm hoặc thành viên cụ thể', + organization: 'Chỉ các thành viên trong doanh nghiệp', + }, + operateGroupAndMember: { + searchPlaceholder: 'Tìm kiếm nhóm và thành viên', + allMembers: 'Tất cả các thành viên', + expand: 'Mở rộng', + noResult: 'Không có kết quả', + }, + title: 'Kiểm soát truy cập ứng dụng web', + description: 'Cài đặt quyền truy cập ứng dụng web', + accessLabel: 'Ai có quyền truy cập', + groups_one: '{{count}} NHÓM', + groups_other: '{{count}} NHÓM', + members_one: '{{count}} THÀNH VIÊN', + members_other: '{{count}} THÀNH VIÊN', + noGroupsOrMembers: 'Không có nhóm hoặc thành viên nào được chọn', + webAppSSONotEnabledTip: 'Vui lòng liên hệ với quản trị viên doanh nghiệp để cấu hình phương thức xác thực ứng dụng web.', + updateSuccess: 'Cập nhật thành công', + }, + publishApp: { + title: 'Ai có thể truy cập ứng dụng web', + notSet: 'Chưa đặt', + notSetDesc: 'Hiện tại không ai có thể truy cập ứng dụng web. Vui lòng thiết lập quyền truy cập.', + }, + noAccessPermission: 'Không được phép truy cập ứng dụng web', + accessControl: 'Kiểm soát truy cập ứng dụng web', } export default translation diff --git a/web/i18n/vi-VN/common.ts b/web/i18n/vi-VN/common.ts index 2bb7eb35d8..323ca60152 100644 --- a/web/i18n/vi-VN/common.ts +++ b/web/i18n/vi-VN/common.ts @@ -145,6 +145,8 @@ const translation = { newDataset: 'Tạo Kiến thức', tools: 'Công cụ', exploreMarketplace: 'Khám phá Marketplace', + appDetail: 'Chi tiết ứng dụng', + account: 'báo cáo', }, userProfile: { settings: 'Cài đặt', @@ -644,6 +646,7 @@ const translation = { license: { expiring_plural: 'Hết hạn sau {{count}} ngày', expiring: 'Hết hạn trong một ngày', + unlimited: 'Vô hạn', }, pagination: { perPage: 'Mục trên mỗi trang', @@ -667,6 +670,7 @@ const translation = { dropImageHere: 'Kéo hình ảnh của bạn vào đây, hoặc', browse: 'duyệt', }, + you: 'Bạn', } export default translation diff --git a/web/i18n/vi-VN/login.ts b/web/i18n/vi-VN/login.ts index ab4ab68f48..cc81bd8193 100644 --- a/web/i18n/vi-VN/login.ts +++ b/web/i18n/vi-VN/login.ts @@ -105,6 +105,11 @@ const translation = { licenseExpired: 'Giấy phép đã hết hạn', licenseExpiredTip: 'Giấy phép Dify Enterprise cho không gian làm việc của bạn đã hết hạn. Vui lòng liên hệ với quản trị viên của bạn để tiếp tục sử dụng Dify.', licenseLostTip: 'Không thể kết nối máy chủ cấp phép Dify. Vui lòng liên hệ với quản trị viên của bạn để tiếp tục sử dụng Dify.', + webapp: { + noLoginMethod: 'Phương thức xác thực chưa được cấu hình cho ứng dụng web', + noLoginMethodTip: 'Vui lòng liên hệ với quản trị viên hệ thống để thêm phương thức xác thực.', + disabled: 'Xác thực webapp đã bị vô hiệu hóa. Vui lòng liên hệ với quản trị hệ thống để kích hoạt nó. Bạn có thể thử sử dụng ứng dụng trực tiếp.', + }, } export default translation diff --git a/web/i18n/vi-VN/plugin.ts b/web/i18n/vi-VN/plugin.ts index 5e5147c69e..889d79f0ca 100644 --- a/web/i18n/vi-VN/plugin.ts +++ b/web/i18n/vi-VN/plugin.ts @@ -62,6 +62,7 @@ const translation = { settings: 'CÀI ĐẶT NGƯỜI DÙNG', empty: 'Nhấp vào nút \'+\' để thêm công cụ. Bạn có thể thêm nhiều công cụ.', unsupportedTitle: 'Hành động không được hỗ trợ', + toolSetting: 'Cài đặt công cụ', }, switchVersion: 'Chuyển đổi phiên bản', endpointDisableTip: 'Tắt điểm cuối', @@ -210,6 +211,7 @@ const translation = { title: 'Plugin', }, difyVersionNotCompatible: 'Phiên bản Dify hiện tại không tương thích với plugin này, vui lòng nâng cấp lên phiên bản tối thiểu cần thiết: {{minimalDifyVersion}}', + requestAPlugin: 'Yêu cầu một plugin', } export default translation diff --git a/web/i18n/vi-VN/workflow.ts b/web/i18n/vi-VN/workflow.ts index 92e94ee5ab..2e0acf0c4d 100644 --- a/web/i18n/vi-VN/workflow.ts +++ b/web/i18n/vi-VN/workflow.ts @@ -660,6 +660,7 @@ const translation = { }, json: 'JSON được tạo bởi công cụ', }, + authorize: 'Ủy quyền', }, questionClassifiers: { model: 'mô hình', diff --git a/web/i18n/zh-Hant/app.ts b/web/i18n/zh-Hant/app.ts index 6b3868745f..f4135d3e73 100644 --- a/web/i18n/zh-Hant/app.ts +++ b/web/i18n/zh-Hant/app.ts @@ -208,6 +208,41 @@ const translation = { structuredTip: '結構化輸出是一項功能,確保模型始終生成符合您提供的 JSON 架構的響應。', notConfiguredTip: '結構化輸出尚未配置', }, + accessItemsDescription: { + anyone: '任何人都可以訪問這個網絡應用程式', + specific: '只有特定的群體或成員可以訪問這個網絡應用程序', + organization: '組織中的任何人都可以訪問該網絡應用程序', + }, + accessControlDialog: { + accessItems: { + anyone: '擁有鏈接的人', + specific: '特定群體或成員', + organization: '只有企業內部成員', + }, + operateGroupAndMember: { + searchPlaceholder: '搜尋群組和成員', + allMembers: '所有成員', + expand: '擴大', + noResult: '沒有結果', + }, + title: '網頁應用程式存取控制', + description: '設定網頁應用程式訪問權限', + accessLabel: '誰可以訪問', + groups_one: '{{count}} 群組', + groups_other: '{{count}} 組', + members_one: '{{count}} 成員', + members_other: '{{count}} 成員', + noGroupsOrMembers: '未選擇任何群組或成員', + webAppSSONotEnabledTip: '請聯絡企業管理員配置網頁應用程式的身份驗證方法。', + updateSuccess: '更新成功', + }, + publishApp: { + title: '誰可以訪問網絡應用程序', + notSet: '未設定', + notSetDesc: '目前沒有人能夠訪問網絡應用程序。請設置權限。', + }, + accessControl: '網頁應用程式存取控制', + noAccessPermission: '沒有權限訪問網絡應用程式', } export default translation diff --git a/web/i18n/zh-Hant/common.ts b/web/i18n/zh-Hant/common.ts index eb2939ecc0..08510c286b 100644 --- a/web/i18n/zh-Hant/common.ts +++ b/web/i18n/zh-Hant/common.ts @@ -646,6 +646,7 @@ const translation = { license: { expiring: '將在1天內過期', expiring_plural: '將在 {{count}} 天后過期', + unlimited: '無限制', }, pagination: { perPage: '每頁項目數', @@ -669,6 +670,7 @@ const translation = { browse: '瀏覽', dropImageHere: '將您的圖片放在這裡,或', }, + you: '你', } export default translation diff --git a/web/i18n/zh-Hant/login.ts b/web/i18n/zh-Hant/login.ts index 6f2b834118..ada0e1bf89 100644 --- a/web/i18n/zh-Hant/login.ts +++ b/web/i18n/zh-Hant/login.ts @@ -105,6 +105,11 @@ const translation = { licenseInactive: '許可證處於非活動狀態', licenseInactiveTip: '您的工作區的 Dify Enterprise 許可證處於非活動狀態。請聯繫您的管理員以繼續使用 Dify。', licenseLostTip: '無法連接 Dify 許可證伺服器。請聯繫您的管理員以繼續使用 Dify。', + webapp: { + noLoginMethod: '未為網絡應用程序配置身份驗證方法', + noLoginMethodTip: '請聯絡系統管理員以添加身份驗證方法。', + disabled: '網頁應用程序身份驗證已被禁用。請聯繫系統管理員以啟用它。您可以嘗試直接使用應用程序。', + }, } export default translation diff --git a/web/i18n/zh-Hant/plugin.ts b/web/i18n/zh-Hant/plugin.ts index 5e93925a6d..3b9040dc91 100644 --- a/web/i18n/zh-Hant/plugin.ts +++ b/web/i18n/zh-Hant/plugin.ts @@ -62,6 +62,7 @@ const translation = { empty: '點擊 『+』 按鈕添加工具。您可以新增多個工具。', unsupportedContent2: '按兩下以切換版本。', paramsTip1: '控制 LLM 推理參數。', + toolSetting: '工具設定', }, actionNum: '{{num}}{{作}}包括', switchVersion: 'Switch 版本', From db488bef51b996b1150d7d848790004143079dc9 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 11:05:08 +0800 Subject: [PATCH 11/73] refactor(api/core/workflow/enums): Rename WORKFLOW_RUN_ID to WORKFLOW_EXECUTION_ID (#20459) Signed-off-by: -LAN- --- api/core/app/apps/advanced_chat/app_runner.py | 2 +- api/core/app/apps/advanced_chat/generate_task_pipeline.py | 2 +- api/core/app/apps/workflow/app_runner.py | 2 +- api/core/app/apps/workflow/generate_task_pipeline.py | 2 +- api/core/workflow/enums.py | 2 +- api/core/workflow/workflow_cycle_manager.py | 2 +- .../unit_tests/core/workflow/test_workflow_cycle_manager.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/core/app/apps/advanced_chat/app_runner.py b/api/core/app/apps/advanced_chat/app_runner.py index c83e06bf15..d9b3833862 100644 --- a/api/core/app/apps/advanced_chat/app_runner.py +++ b/api/core/app/apps/advanced_chat/app_runner.py @@ -140,7 +140,7 @@ class AdvancedChatAppRunner(WorkflowBasedAppRunner): SystemVariableKey.DIALOGUE_COUNT: self._dialogue_count, SystemVariableKey.APP_ID: app_config.app_id, SystemVariableKey.WORKFLOW_ID: app_config.workflow_id, - SystemVariableKey.WORKFLOW_RUN_ID: self.application_generate_entity.workflow_run_id, + SystemVariableKey.WORKFLOW_EXECUTION_ID: self.application_generate_entity.workflow_run_id, } # init variable pool diff --git a/api/core/app/apps/advanced_chat/generate_task_pipeline.py b/api/core/app/apps/advanced_chat/generate_task_pipeline.py index ffce11187b..112e178b82 100644 --- a/api/core/app/apps/advanced_chat/generate_task_pipeline.py +++ b/api/core/app/apps/advanced_chat/generate_task_pipeline.py @@ -124,7 +124,7 @@ class AdvancedChatAppGenerateTaskPipeline: SystemVariableKey.DIALOGUE_COUNT: dialogue_count, SystemVariableKey.APP_ID: application_generate_entity.app_config.app_id, SystemVariableKey.WORKFLOW_ID: workflow.id, - SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_run_id, + SystemVariableKey.WORKFLOW_EXECUTION_ID: application_generate_entity.workflow_run_id, }, workflow_info=CycleManagerWorkflowInfo( workflow_id=workflow.id, diff --git a/api/core/app/apps/workflow/app_runner.py b/api/core/app/apps/workflow/app_runner.py index c93a49b7e4..b59e34e222 100644 --- a/api/core/app/apps/workflow/app_runner.py +++ b/api/core/app/apps/workflow/app_runner.py @@ -95,7 +95,7 @@ class WorkflowAppRunner(WorkflowBasedAppRunner): SystemVariableKey.USER_ID: user_id, SystemVariableKey.APP_ID: app_config.app_id, SystemVariableKey.WORKFLOW_ID: app_config.workflow_id, - SystemVariableKey.WORKFLOW_RUN_ID: self.application_generate_entity.workflow_execution_id, + SystemVariableKey.WORKFLOW_EXECUTION_ID: self.application_generate_entity.workflow_execution_id, } variable_pool = VariablePool( diff --git a/api/core/app/apps/workflow/generate_task_pipeline.py b/api/core/app/apps/workflow/generate_task_pipeline.py index e678774fae..fb0ea80a3a 100644 --- a/api/core/app/apps/workflow/generate_task_pipeline.py +++ b/api/core/app/apps/workflow/generate_task_pipeline.py @@ -113,7 +113,7 @@ class WorkflowAppGenerateTaskPipeline: SystemVariableKey.USER_ID: user_session_id, SystemVariableKey.APP_ID: application_generate_entity.app_config.app_id, SystemVariableKey.WORKFLOW_ID: workflow.id, - SystemVariableKey.WORKFLOW_RUN_ID: application_generate_entity.workflow_execution_id, + SystemVariableKey.WORKFLOW_EXECUTION_ID: application_generate_entity.workflow_execution_id, }, workflow_info=CycleManagerWorkflowInfo( workflow_id=workflow.id, diff --git a/api/core/workflow/enums.py b/api/core/workflow/enums.py index 9642efa1a5..b52a2b0e6e 100644 --- a/api/core/workflow/enums.py +++ b/api/core/workflow/enums.py @@ -13,4 +13,4 @@ class SystemVariableKey(StrEnum): DIALOGUE_COUNT = "dialogue_count" APP_ID = "app_id" WORKFLOW_ID = "workflow_id" - WORKFLOW_RUN_ID = "workflow_run_id" + WORKFLOW_EXECUTION_ID = "workflow_run_id" diff --git a/api/core/workflow/workflow_cycle_manager.py b/api/core/workflow/workflow_cycle_manager.py index 6365ab53a2..b88f9edd03 100644 --- a/api/core/workflow/workflow_cycle_manager.py +++ b/api/core/workflow/workflow_cycle_manager.py @@ -65,7 +65,7 @@ class WorkflowCycleManager: # init workflow run # TODO: This workflow_run_id should always not be None, maybe we can use a more elegant way to handle this - execution_id = str(self._workflow_system_variables.get(SystemVariableKey.WORKFLOW_RUN_ID) or uuid4()) + execution_id = str(self._workflow_system_variables.get(SystemVariableKey.WORKFLOW_EXECUTION_ID) or uuid4()) execution = WorkflowExecution.new( id_=execution_id, workflow_id=self._workflow_info.workflow_id, diff --git a/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py b/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py index db75370d67..fddc182594 100644 --- a/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py +++ b/api/tests/unit_tests/core/workflow/test_workflow_cycle_manager.py @@ -73,7 +73,7 @@ def real_workflow_system_variables(): SystemVariableKey.USER_ID: "test-user-id", SystemVariableKey.APP_ID: "test-app-id", SystemVariableKey.WORKFLOW_ID: "test-workflow-id", - SystemVariableKey.WORKFLOW_RUN_ID: "test-workflow-run-id", + SystemVariableKey.WORKFLOW_EXECUTION_ID: "test-workflow-run-id", } From 156bb8238d1d2d6769c7b03701324bc539b39ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?= Date: Fri, 30 May 2025 11:25:46 +0800 Subject: [PATCH 12/73] fix: some display error in dark mode (#20469) --- .../components/base/chat/chat/question.tsx | 2 +- .../embedded-chatbot/theme/theme-context.ts | 4 +-- .../datasets/create/step-two/index.tsx | 6 ++--- .../detail/batch-modal/csv-downloader.tsx | 26 +++++++++---------- .../detail/batch-modal/csv-uploader.tsx | 16 ++++++------ .../documents/detail/batch-modal/index.tsx | 4 +-- .../datasets/settings/form/index.tsx | 2 +- web/themes/dark.css | 1 + web/themes/light.css | 1 + web/themes/tailwind-theme-var-define.ts | 1 + 10 files changed, 32 insertions(+), 31 deletions(-) diff --git a/web/app/components/base/chat/chat/question.tsx b/web/app/components/base/chat/chat/question.tsx index 8fc49d1978..30077125f9 100644 --- a/web/app/components/base/chat/chat/question.tsx +++ b/web/app/components/base/chat/chat/question.tsx @@ -117,7 +117,7 @@ const Question: FC = ({
{ diff --git a/web/app/components/base/chat/embedded-chatbot/theme/theme-context.ts b/web/app/components/base/chat/embedded-chatbot/theme/theme-context.ts index d4d617d4b7..321997ab1d 100644 --- a/web/app/components/base/chat/embedded-chatbot/theme/theme-context.ts +++ b/web/app/components/base/chat/embedded-chatbot/theme/theme-context.ts @@ -12,8 +12,7 @@ export class Theme { public colorPathOnHeader = 'text-text-primary-on-surface' public backgroundButtonDefaultColorStyle = 'backgroundColor: #1C64F2' public roundedBackgroundColorStyle = 'backgroundColor: rgb(245 248 255)' - public chatBubbleColorStyle = 'backgroundColor: rgb(225 239 254)' - public chatBubbleColor = 'rgb(225 239 254)' + public chatBubbleColorStyle = '' constructor(chatColorTheme: string | null = null, chatColorThemeInverted = false) { this.chatColorTheme = chatColorTheme @@ -29,7 +28,6 @@ export class Theme { this.backgroundButtonDefaultColorStyle = `backgroundColor: ${this.primaryColor}; color: ${this.colorFontOnHeaderStyle};` this.roundedBackgroundColorStyle = `backgroundColor: ${hexToRGBA(this.primaryColor, 0.05)}` this.chatBubbleColorStyle = `backgroundColor: ${hexToRGBA(this.primaryColor, 0.15)}` - this.chatBubbleColor = `${hexToRGBA(this.primaryColor, 0.15)}` } } diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index 6b6580ae7e..52c5195bbf 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -865,10 +865,10 @@ const StepTwo = ({ <> setIsQAConfirmDialogOpen(false)} className='w-[432px]'>
-

+

{t('datasetCreation.stepTwo.qaSwitchHighQualityTipTitle')}

-

+

{t('datasetCreation.stepTwo.qaSwitchHighQualityTipContent')}

@@ -928,7 +928,7 @@ const StepTwo = ({
)} {hasSetIndexType && indexType === IndexingType.ECONOMICAL && ( -
+
{t('datasetCreation.stepTwo.indexSettingTip')} {t('datasetCreation.stepTwo.datasetSettingLink')}
diff --git a/web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx b/web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx index 90bdb707df..7f3be965b3 100644 --- a/web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx +++ b/web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx @@ -50,20 +50,20 @@ const CSVDownload: FC<{ docForm: ChunkingMode }> = ({ docForm }) => { return (
-
{t('share.generation.csvStructureTitle')}
+
{t('share.generation.csvStructureTitle')}
{docForm === ChunkingMode.qa && ( - - +
+ - - + + - + - - + + @@ -73,15 +73,15 @@ const CSVDownload: FC<{ docForm: ChunkingMode }> = ({ docForm }) => {
{t('datasetDocuments.list.batchModal.question')}{t('datasetDocuments.list.batchModal.answer')}{t('datasetDocuments.list.batchModal.question')}{t('datasetDocuments.list.batchModal.answer')}
{t('datasetDocuments.list.batchModal.question')} 1{t('datasetDocuments.list.batchModal.answer')} 1{t('datasetDocuments.list.batchModal.question')} 1{t('datasetDocuments.list.batchModal.answer')} 1
{t('datasetDocuments.list.batchModal.question')} 2
)} {docForm === ChunkingMode.text && ( - - +
+ - + - + - + diff --git a/web/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx b/web/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx index 471bf7be2f..c2224296d6 100644 --- a/web/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx +++ b/web/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx @@ -93,29 +93,29 @@ const CSVUploader: FC = ({ />
{!file && ( -
+
-
+
{t('datasetDocuments.list.batchModal.csvUploadTitle')} - {t('datasetDocuments.list.batchModal.browse')} + {t('datasetDocuments.list.batchModal.browse')}
{dragging &&
}
)} {file && ( -
+
- {file.name.replace(/.csv$/, '')} - .csv + {file.name.replace(/.csv$/, '')} + .csv
-
+
- +
diff --git a/web/app/components/datasets/documents/detail/batch-modal/index.tsx b/web/app/components/datasets/documents/detail/batch-modal/index.tsx index 775d755106..614471c565 100644 --- a/web/app/components/datasets/documents/detail/batch-modal/index.tsx +++ b/web/app/components/datasets/documents/detail/batch-modal/index.tsx @@ -41,9 +41,9 @@ const BatchModal: FC = ({ return ( -
{t('datasetDocuments.list.batchModal.title')}
+
{t('datasetDocuments.list.batchModal.title')}
- +
{
- {t('datasetSettings.form.upgradeHighQualityTip')} + {t('datasetSettings.form.upgradeHighQualityTip')}
}
diff --git a/web/themes/dark.css b/web/themes/dark.css index edbd9de7b0..fbfacf1f45 100644 --- a/web/themes/dark.css +++ b/web/themes/dark.css @@ -386,6 +386,7 @@ html[data-theme="dark"] { --color-background-gradient-bg-fill-chat-bg-2: #1d1d20; --color-background-gradient-bg-fill-chat-bubble-bg-1: #c8ceda14; --color-background-gradient-bg-fill-chat-bubble-bg-2: #c8ceda05; + --color-background-gradient-bg-fill-chat-bubble-bg-3: #a5bddb; --color-background-gradient-bg-fill-debug-bg-1: #c8ceda14; --color-background-gradient-bg-fill-debug-bg-2: #18181b0a; diff --git a/web/themes/light.css b/web/themes/light.css index 1d96658963..8a3f9d9d48 100644 --- a/web/themes/light.css +++ b/web/themes/light.css @@ -386,6 +386,7 @@ html[data-theme="light"] { --color-background-gradient-bg-fill-chat-bg-2: #f2f4f7; --color-background-gradient-bg-fill-chat-bubble-bg-1: #ffffff; --color-background-gradient-bg-fill-chat-bubble-bg-2: #ffffff99; + --color-background-gradient-bg-fill-chat-bubble-bg-3: #e1effe; --color-background-gradient-bg-fill-debug-bg-1: #ffffff00; --color-background-gradient-bg-fill-debug-bg-2: #c8ceda24; diff --git a/web/themes/tailwind-theme-var-define.ts b/web/themes/tailwind-theme-var-define.ts index 62c0ed82c7..11189441ee 100644 --- a/web/themes/tailwind-theme-var-define.ts +++ b/web/themes/tailwind-theme-var-define.ts @@ -386,6 +386,7 @@ const vars = { 'background-gradient-bg-fill-chat-bg-2': 'var(--color-background-gradient-bg-fill-chat-bg-2)', 'background-gradient-bg-fill-chat-bubble-bg-1': 'var(--color-background-gradient-bg-fill-chat-bubble-bg-1)', 'background-gradient-bg-fill-chat-bubble-bg-2': 'var(--color-background-gradient-bg-fill-chat-bubble-bg-2)', + 'background-gradient-bg-fill-chat-bubble-bg-3': 'var(--color-background-gradient-bg-fill-chat-bubble-bg-3)', 'background-gradient-bg-fill-debug-bg-1': 'var(--color-background-gradient-bg-fill-debug-bg-1)', 'background-gradient-bg-fill-debug-bg-2': 'var(--color-background-gradient-bg-fill-debug-bg-2)', From f65c2fcb1db09c59f7e3b091ea0623e8b814a763 Mon Sep 17 00:00:00 2001 From: sayThQ199 <18852951350@163.com> Date: Fri, 30 May 2025 11:31:50 +0800 Subject: [PATCH 13/73] Refactor/markdown component split (#20177) --- .../base/markdown-blocks/audio-block.tsx | 21 ++ .../code-block.tsx} | 215 +----------------- .../components/base/markdown-blocks/img.tsx | 13 ++ .../components/base/markdown-blocks/index.ts | 18 ++ .../components/base/markdown-blocks/link.tsx | 21 ++ .../base/markdown-blocks/paragraph.tsx | 27 +++ .../base/markdown-blocks/pre-code.tsx | 21 ++ .../base/markdown-blocks/script-block.tsx | 15 ++ .../base/markdown-blocks/video-block.tsx | 21 ++ .../base/markdown/error-boundary.tsx | 33 +++ web/app/components/base/markdown/index.tsx | 87 +++++++ .../base/markdown/markdown-utils.ts | 37 +++ 12 files changed, 319 insertions(+), 210 deletions(-) create mode 100644 web/app/components/base/markdown-blocks/audio-block.tsx rename web/app/components/base/{markdown.tsx => markdown-blocks/code-block.tsx} (63%) create mode 100644 web/app/components/base/markdown-blocks/img.tsx create mode 100644 web/app/components/base/markdown-blocks/index.ts create mode 100644 web/app/components/base/markdown-blocks/link.tsx create mode 100644 web/app/components/base/markdown-blocks/paragraph.tsx create mode 100644 web/app/components/base/markdown-blocks/pre-code.tsx create mode 100644 web/app/components/base/markdown-blocks/script-block.tsx create mode 100644 web/app/components/base/markdown-blocks/video-block.tsx create mode 100644 web/app/components/base/markdown/error-boundary.tsx create mode 100644 web/app/components/base/markdown/index.tsx create mode 100644 web/app/components/base/markdown/markdown-utils.ts diff --git a/web/app/components/base/markdown-blocks/audio-block.tsx b/web/app/components/base/markdown-blocks/audio-block.tsx new file mode 100644 index 0000000000..09001f105b --- /dev/null +++ b/web/app/components/base/markdown-blocks/audio-block.tsx @@ -0,0 +1,21 @@ +/** + * @fileoverview AudioBlock component for rendering audio elements in Markdown. + * Extracted from the main markdown renderer for modularity. + * Uses the AudioGallery component to display audio players. + */ +import React, { memo } from 'react' +import AudioGallery from '@/app/components/base/audio-gallery' + +const AudioBlock: any = memo(({ node }: any) => { + const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src) + if (srcs.length === 0) { + const src = node.properties?.src + if (src) + return + return null + } + return +}) +AudioBlock.displayName = 'AudioBlock' + +export default AudioBlock diff --git a/web/app/components/base/markdown.tsx b/web/app/components/base/markdown-blocks/code-block.tsx similarity index 63% rename from web/app/components/base/markdown.tsx rename to web/app/components/base/markdown-blocks/code-block.tsx index a47d93268c..9f8a6a87bb 100644 --- a/web/app/components/base/markdown.tsx +++ b/web/app/components/base/markdown-blocks/code-block.tsx @@ -1,34 +1,19 @@ -import ReactMarkdown from 'react-markdown' +import { memo, useEffect, useMemo, useRef, useState } from 'react' import ReactEcharts from 'echarts-for-react' -import 'katex/dist/katex.min.css' -import RemarkMath from 'remark-math' -import RemarkBreaks from 'remark-breaks' -import RehypeKatex from 'rehype-katex' -import RemarkGfm from 'remark-gfm' -import RehypeRaw from 'rehype-raw' import SyntaxHighlighter from 'react-syntax-highlighter' import { atelierHeathDark, atelierHeathLight, } from 'react-syntax-highlighter/dist/esm/styles/hljs' -import { Component, memo, useEffect, useMemo, useRef, useState } from 'react' -import { flow } from 'lodash-es' import ActionButton from '@/app/components/base/action-button' import CopyIcon from '@/app/components/base/copy-icon' import SVGBtn from '@/app/components/base/svg' import Flowchart from '@/app/components/base/mermaid' -import ImageGallery from '@/app/components/base/image-gallery' -import { useChatContext } from '@/app/components/base/chat/chat/context' -import VideoGallery from '@/app/components/base/video-gallery' -import AudioGallery from '@/app/components/base/audio-gallery' -import MarkdownButton from '@/app/components/base/markdown-blocks/button' -import MarkdownForm from '@/app/components/base/markdown-blocks/form' -import MarkdownMusic from '@/app/components/base/markdown-blocks/music' -import ThinkBlock from '@/app/components/base/markdown-blocks/think-block' import { Theme } from '@/types/app' import useTheme from '@/hooks/use-theme' -import cn from '@/utils/classnames' -import SVGRenderer from './svg-gallery' +import SVGRenderer from '../svg-gallery' // Assumes svg-gallery.tsx is in /base directory +import MarkdownMusic from '@/app/components/base/markdown-blocks/music' +import ErrorBoundary from '@/app/components/base/markdown/error-boundary' // Available language https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/AVAILABLE_LANGUAGES_HLJS.MD const capitalizationLanguageNameMap: Record = { @@ -64,50 +49,6 @@ const getCorrectCapitalizationLanguageName = (language: string) => { return language.charAt(0).toUpperCase() + language.substring(1) } -const preprocessLaTeX = (content: string) => { - if (typeof content !== 'string') - return content - - const codeBlockRegex = /```[\s\S]*?```/g - const codeBlocks = content.match(codeBlockRegex) || [] - let processedContent = content.replace(codeBlockRegex, 'CODE_BLOCK_PLACEHOLDER') - - processedContent = flow([ - (str: string) => str.replace(/\\\[(.*?)\\\]/g, (_, equation) => `$$${equation}$$`), - (str: string) => str.replace(/\\\[([\s\S]*?)\\\]/g, (_, equation) => `$$${equation}$$`), - (str: string) => str.replace(/\\\((.*?)\\\)/g, (_, equation) => `$$${equation}$$`), - (str: string) => str.replace(/(^|[^\\])\$(.+?)\$/g, (_, prefix, equation) => `${prefix}$${equation}$`), - ])(processedContent) - - codeBlocks.forEach((block) => { - processedContent = processedContent.replace('CODE_BLOCK_PLACEHOLDER', block) - }) - - return processedContent -} - -const preprocessThinkTag = (content: string) => { - const thinkOpenTagRegex = /\n/g - const thinkCloseTagRegex = /\n<\/think>/g - return flow([ - (str: string) => str.replace(thinkOpenTagRegex, '
\n'), - (str: string) => str.replace(thinkCloseTagRegex, '\n[ENDTHINKFLAG]
'), - ])(content) -} - -export function PreCode(props: { children: any }) { - const ref = useRef(null) - - return ( -
-      
-      {props.children}
-    
- ) -} - // **Add code block // Avoid error #185 (Maximum update depth exceeded. // This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. @@ -444,150 +385,4 @@ const CodeBlock: any = memo(({ inline, className, children = '', ...props }: any }) CodeBlock.displayName = 'CodeBlock' -const VideoBlock: any = memo(({ node }: any) => { - const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src) - if (srcs.length === 0) { - const src = node.properties?.src - if (src) - return - return null - } - return -}) -VideoBlock.displayName = 'VideoBlock' - -const AudioBlock: any = memo(({ node }: any) => { - const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src) - if (srcs.length === 0) { - const src = node.properties?.src - if (src) - return - return null - } - return -}) -AudioBlock.displayName = 'AudioBlock' - -const ScriptBlock = memo(({ node }: any) => { - const scriptContent = node.children[0]?.value || '' - return `` -}) -ScriptBlock.displayName = 'ScriptBlock' - -const Paragraph = (paragraph: any) => { - const { node }: any = paragraph - const children_node = node.children - if (children_node && children_node[0] && 'tagName' in children_node[0] && children_node[0].tagName === 'img') { - return ( -
- - { - Array.isArray(paragraph.children) && paragraph.children.length > 1 && ( -
{paragraph.children.slice(1)}
- ) - } -
- ) - } - return

{paragraph.children}

-} - -const Img = ({ src }: any) => { - return
-} - -const Link = ({ node, children, ...props }: any) => { - if (node.properties?.href && node.properties.href?.toString().startsWith('abbr')) { - // eslint-disable-next-line react-hooks/rules-of-hooks - const { onSend } = useChatContext() - const hidden_text = decodeURIComponent(node.properties.href.toString().split('abbr:')[1]) - - return onSend?.(hidden_text)} title={node.children[0]?.value || ''}>{node.children[0]?.value || ''} - } - else { - return {children || 'Download'} - } -} - -export function Markdown(props: { content: string; className?: string; customDisallowedElements?: string[] }) { - const latexContent = flow([ - preprocessThinkTag, - preprocessLaTeX, - ])(props.content) - - return ( -
- { - return (tree) => { - const iterate = (node: any) => { - if (node.type === 'element' && node.properties?.ref) - delete node.properties.ref - - if (node.type === 'element' && !/^[a-z][a-z0-9]*$/i.test(node.tagName)) { - node.type = 'text' - node.value = `<${node.tagName}` - } - - if (node.children) - node.children.forEach(iterate) - } - tree.children.forEach(iterate) - } - }, - ]} - disallowedElements={['iframe', 'head', 'html', 'meta', 'link', 'style', 'body', ...(props.customDisallowedElements || [])]} - components={{ - code: CodeBlock, - img: Img, - video: VideoBlock, - audio: AudioBlock, - a: Link, - p: Paragraph, - button: MarkdownButton, - form: MarkdownForm, - script: ScriptBlock as any, - details: ThinkBlock, - }} - > - {/* Markdown detect has problem. */} - {latexContent} - -
- ) -} - -// **Add an ECharts runtime error handler -// Avoid error #7832 (Crash when ECharts accesses undefined objects) -// This can happen when a component attempts to access an undefined object that references an unregistered map, causing the program to crash. - -export default class ErrorBoundary extends Component { - constructor(props: any) { - super(props) - this.state = { hasError: false } - } - - componentDidCatch(error: any, errorInfo: any) { - this.setState({ hasError: true }) - console.error(error, errorInfo) - } - - render() { - // eslint-disable-next-line ts/ban-ts-comment - // @ts-expect-error - if (this.state.hasError) - return
Oops! An error occurred. This could be due to an ECharts runtime error or invalid SVG content.
(see the browser console for more information)
- // eslint-disable-next-line ts/ban-ts-comment - // @ts-expect-error - return this.props.children - } -} +export default CodeBlock diff --git a/web/app/components/base/markdown-blocks/img.tsx b/web/app/components/base/markdown-blocks/img.tsx new file mode 100644 index 0000000000..33fce13f0b --- /dev/null +++ b/web/app/components/base/markdown-blocks/img.tsx @@ -0,0 +1,13 @@ +/** + * @fileoverview Img component for rendering tags in Markdown. + * Extracted from the main markdown renderer for modularity. + * Uses the ImageGallery component to display images. + */ +import React from 'react' +import ImageGallery from '@/app/components/base/image-gallery' + +const Img = ({ src }: any) => { + return
+} + +export default Img diff --git a/web/app/components/base/markdown-blocks/index.ts b/web/app/components/base/markdown-blocks/index.ts new file mode 100644 index 0000000000..ba68b4e8b1 --- /dev/null +++ b/web/app/components/base/markdown-blocks/index.ts @@ -0,0 +1,18 @@ +/** + * @fileoverview Barrel file for all markdown block components. + * This allows for cleaner imports in other parts of the application. + */ + +export { default as AudioBlock } from './audio-block' +export { default as CodeBlock } from './code-block' +export { default as Img } from './img' +export { default as Link } from './link' +export { default as Paragraph } from './paragraph' +export { default as PreCode } from './pre-code' +export { default as ScriptBlock } from './script-block' +export { default as VideoBlock } from './video-block' + +// Assuming these are also standalone components in this directory intended for Markdown rendering +export { default as MarkdownButton } from './button' +export { default as MarkdownForm } from './form' +export { default as ThinkBlock } from './think-block' diff --git a/web/app/components/base/markdown-blocks/link.tsx b/web/app/components/base/markdown-blocks/link.tsx new file mode 100644 index 0000000000..b243a525a0 --- /dev/null +++ b/web/app/components/base/markdown-blocks/link.tsx @@ -0,0 +1,21 @@ +/** + * @fileoverview Link component for rendering tags in Markdown. + * Extracted from the main markdown renderer for modularity. + * Handles special rendering for "abbr:" type links for interactive chat actions. + */ +import React from 'react' +import { useChatContext } from '@/app/components/base/chat/chat/context' + +const Link = ({ node, children, ...props }: any) => { + const { onSend } = useChatContext() + if (node.properties?.href && node.properties.href?.toString().startsWith('abbr')) { + const hidden_text = decodeURIComponent(node.properties.href.toString().split('abbr:')[1]) + + return onSend?.(hidden_text)} title={node.children[0]?.value || ''}>{node.children[0]?.value || ''} + } + else { + return {children || 'Download'} + } +} + +export default Link diff --git a/web/app/components/base/markdown-blocks/paragraph.tsx b/web/app/components/base/markdown-blocks/paragraph.tsx new file mode 100644 index 0000000000..fb1612477a --- /dev/null +++ b/web/app/components/base/markdown-blocks/paragraph.tsx @@ -0,0 +1,27 @@ +/** + * @fileoverview Paragraph component for rendering

tags in Markdown. + * Extracted from the main markdown renderer for modularity. + * Handles special rendering for paragraphs that directly contain an image. + */ +import React from 'react' +import ImageGallery from '@/app/components/base/image-gallery' + +const Paragraph = (paragraph: any) => { + const { node }: any = paragraph + const children_node = node.children + if (children_node && children_node[0] && 'tagName' in children_node[0] && children_node[0].tagName === 'img') { + return ( +

+ + { + Array.isArray(paragraph.children) && paragraph.children.length > 1 && ( +
{paragraph.children.slice(1)}
+ ) + } +
+ ) + } + return

{paragraph.children}

+} + +export default Paragraph diff --git a/web/app/components/base/markdown-blocks/pre-code.tsx b/web/app/components/base/markdown-blocks/pre-code.tsx new file mode 100644 index 0000000000..a9d0cfb9aa --- /dev/null +++ b/web/app/components/base/markdown-blocks/pre-code.tsx @@ -0,0 +1,21 @@ +/** + * @fileoverview PreCode component for rendering
 tags in Markdown.
+ * Extracted from the main markdown renderer for modularity.
+ * This is a simple wrapper around the HTML 
 element.
+ */
+import React, { useRef } from 'react'
+
+function PreCode(props: { children: any }) {
+  const ref = useRef(null)
+
+  return (
+    
+      
+      {props.children}
+    
+ ) +} + +export default PreCode diff --git a/web/app/components/base/markdown-blocks/script-block.tsx b/web/app/components/base/markdown-blocks/script-block.tsx new file mode 100644 index 0000000000..921e2bf049 --- /dev/null +++ b/web/app/components/base/markdown-blocks/script-block.tsx @@ -0,0 +1,15 @@ +/** + * @fileoverview ScriptBlock component for handling ` +}) +ScriptBlock.displayName = 'ScriptBlock' + +export default ScriptBlock diff --git a/web/app/components/base/markdown-blocks/video-block.tsx b/web/app/components/base/markdown-blocks/video-block.tsx new file mode 100644 index 0000000000..9f1a36f678 --- /dev/null +++ b/web/app/components/base/markdown-blocks/video-block.tsx @@ -0,0 +1,21 @@ +/** + * @fileoverview VideoBlock component for rendering video elements in Markdown. + * Extracted from the main markdown renderer for modularity. + * Uses the VideoGallery component to display videos. + */ +import React, { memo } from 'react' +import VideoGallery from '@/app/components/base/video-gallery' + +const VideoBlock: any = memo(({ node }: any) => { + const srcs = node.children.filter((child: any) => 'properties' in child).map((child: any) => (child as any).properties.src) + if (srcs.length === 0) { + const src = node.properties?.src + if (src) + return + return null + } + return +}) +VideoBlock.displayName = 'VideoBlock' + +export default VideoBlock diff --git a/web/app/components/base/markdown/error-boundary.tsx b/web/app/components/base/markdown/error-boundary.tsx new file mode 100644 index 0000000000..0e6876191a --- /dev/null +++ b/web/app/components/base/markdown/error-boundary.tsx @@ -0,0 +1,33 @@ +/** + * @fileoverview ErrorBoundary component for React. + * This component was extracted from the main markdown renderer. + * It catches JavaScript errors anywhere in its child component tree, + * logs those errors, and displays a fallback UI instead of the crashed component tree. + * Primarily used around complex rendering logic like ECharts or SVG within Markdown. + */ +import React, { Component } from 'react' +// **Add an ECharts runtime error handler +// Avoid error #7832 (Crash when ECharts accesses undefined objects) +// This can happen when a component attempts to access an undefined object that references an unregistered map, causing the program to crash. + +export default class ErrorBoundary extends Component { + constructor(props: any) { + super(props) + this.state = { hasError: false } + } + + componentDidCatch(error: any, errorInfo: any) { + this.setState({ hasError: true }) + console.error(error, errorInfo) + } + + render() { + // eslint-disable-next-line ts/ban-ts-comment + // @ts-expect-error + if (this.state.hasError) + return
Oops! An error occurred. This could be due to an ECharts runtime error or invalid SVG content.
(see the browser console for more information)
+ // eslint-disable-next-line ts/ban-ts-comment + // @ts-expect-error + return this.props.children + } +} diff --git a/web/app/components/base/markdown/index.tsx b/web/app/components/base/markdown/index.tsx new file mode 100644 index 0000000000..0e0dc41cf2 --- /dev/null +++ b/web/app/components/base/markdown/index.tsx @@ -0,0 +1,87 @@ +import ReactMarkdown from 'react-markdown' +import 'katex/dist/katex.min.css' +import RemarkMath from 'remark-math' +import RemarkBreaks from 'remark-breaks' +import RehypeKatex from 'rehype-katex' +import RemarkGfm from 'remark-gfm' +import RehypeRaw from 'rehype-raw' +import { flow } from 'lodash-es' +import cn from '@/utils/classnames' +import { preprocessLaTeX, preprocessThinkTag } from './markdown-utils' +import { + AudioBlock, + CodeBlock, + Img, + Link, + MarkdownButton, + MarkdownForm, + Paragraph, + ScriptBlock, + ThinkBlock, + VideoBlock, +} from '@/app/components/base/markdown-blocks' + +/** + * @fileoverview Main Markdown rendering component. + * This file was refactored to extract individual block renderers and utility functions + * into separate modules for better organization and maintainability as of [Date of refactor]. + * Further refactoring candidates (custom block components not fitting general categories) + * are noted in their respective files if applicable. + */ + +export function Markdown(props: { content: string; className?: string; customDisallowedElements?: string[] }) { + const latexContent = flow([ + preprocessThinkTag, + preprocessLaTeX, + ])(props.content) + + return ( +
+ { + return (tree: any) => { + const iterate = (node: any) => { + if (node.type === 'element' && node.properties?.ref) + delete node.properties.ref + + if (node.type === 'element' && !/^[a-z][a-z0-9]*$/i.test(node.tagName)) { + node.type = 'text' + node.value = `<${node.tagName}` + } + + if (node.children) + node.children.forEach(iterate) + } + tree.children.forEach(iterate) + } + }, + ]} + disallowedElements={['iframe', 'head', 'html', 'meta', 'link', 'style', 'body', ...(props.customDisallowedElements || [])]} + components={{ + code: CodeBlock, + img: Img, + video: VideoBlock, + audio: AudioBlock, + a: Link, + p: Paragraph, + button: MarkdownButton, + form: MarkdownForm, + script: ScriptBlock as any, + details: ThinkBlock, + }} + > + {/* Markdown detect has problem. */} + {latexContent} + +
+ ) +} diff --git a/web/app/components/base/markdown/markdown-utils.ts b/web/app/components/base/markdown/markdown-utils.ts new file mode 100644 index 0000000000..ff7dd5db01 --- /dev/null +++ b/web/app/components/base/markdown/markdown-utils.ts @@ -0,0 +1,37 @@ +/** + * @fileoverview Utility functions for preprocessing Markdown content. + * These functions were extracted from the main markdown renderer for better separation of concerns. + * Includes preprocessing for LaTeX and custom "think" tags. + */ +import { flow } from 'lodash-es' + +export const preprocessLaTeX = (content: string) => { + if (typeof content !== 'string') + return content + + const codeBlockRegex = /```[\s\S]*?```/g + const codeBlocks = content.match(codeBlockRegex) || [] + let processedContent = content.replace(codeBlockRegex, 'CODE_BLOCK_PLACEHOLDER') + + processedContent = flow([ + (str: string) => str.replace(/\\\[(.*?)\\\]/g, (_, equation) => `$$${equation}$$`), + (str: string) => str.replace(/\\\[([\s\S]*?)\\\]/g, (_, equation) => `$$${equation}$$`), + (str: string) => str.replace(/\\\((.*?)\\\)/g, (_, equation) => `$$${equation}$$`), + (str: string) => str.replace(/(^|[^\\])\$(.+?)\$/g, (_, prefix, equation) => `${prefix}$${equation}$`), + ])(processedContent) + + codeBlocks.forEach((block) => { + processedContent = processedContent.replace('CODE_BLOCK_PLACEHOLDER', block) + }) + + return processedContent +} + +export const preprocessThinkTag = (content: string) => { + const thinkOpenTagRegex = /\n/g + const thinkCloseTagRegex = /\n<\/think>/g + return flow([ + (str: string) => str.replace(thinkOpenTagRegex, '
\n'), + (str: string) => str.replace(thinkCloseTagRegex, '\n[ENDTHINKFLAG]
'), + ])(content) +} From 9b47f9f7860e152e26e76f6ee8d15ac1f1231c07 Mon Sep 17 00:00:00 2001 From: Wu Tianwei <30284043+WTW0313@users.noreply.github.com> Date: Fri, 30 May 2025 13:54:12 +0800 Subject: [PATCH 14/73] fix(json-schema-editor): Add container reference for resize observer in CodeEditor; Update language hook and help doc URL in JsonSchemaConfig (#20488) --- .../json-schema-config-modal/code-editor.tsx | 21 ++++++++++++++++--- .../json-schema-config.tsx | 14 +++---------- .../schema-editor.tsx | 2 +- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/code-editor.tsx b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/code-editor.tsx index a3c2552b45..2ae7fec78d 100644 --- a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/code-editor.tsx +++ b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/code-editor.tsx @@ -28,6 +28,7 @@ const CodeEditor: FC = ({ const { theme } = useTheme() const monacoRef = useRef(null) const editorRef = useRef(null) + const containerRef = useRef(null) useEffect(() => { if (monacoRef.current) { @@ -74,6 +75,19 @@ const CodeEditor: FC = ({ onUpdate?.(value) }, [onUpdate]) + useEffect(() => { + const resizeObserver = new ResizeObserver(() => { + editorRef.current?.layout() + }) + + if (containerRef.current) + resizeObserver.observe(containerRef.current) + + return () => { + resizeObserver.disconnect() + } + }, []) + return (
@@ -102,9 +116,11 @@ const CodeEditor: FC = ({
-
+
= ({ scrollBeyondLastLine: false, wordWrap: 'on', wrappingIndent: 'same', - // Add these options overviewRulerBorder: false, hideCursorInOverviewRuler: true, renderLineHighlightOnlyWhenFocus: false, diff --git a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx index 344d02c011..2b8574b285 100644 --- a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx +++ b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-config.tsx @@ -21,7 +21,7 @@ import { MittProvider, VisualEditorContextProvider, useMittContext } from './vis import ErrorMessage from './error-message' import { useVisualEditorStore } from './visual-editor/store' import Toast from '@/app/components/base/toast' -import { useGetLanguage } from '@/context/i18n' +import { useGetDocLanguage } from '@/context/i18n' import { JSON_SCHEMA_MAX_DEPTH } from '@/config' type JsonSchemaConfigProps = { @@ -47,21 +47,13 @@ const DEFAULT_SCHEMA: SchemaRoot = { additionalProperties: false, } -const HELP_DOC_URL = { - zh_Hans: 'https://docs.dify.ai/zh-hans/guides/workflow/structured-outputs', - en_US: 'https://docs.dify.ai/en/guides/workflow/structured-outputs', - ja_JP: 'https://docs.dify.ai/ja-jp/guides/workflow/structured-outputs', -} - -type LocaleKey = keyof typeof HELP_DOC_URL - const JsonSchemaConfig: FC = ({ defaultSchema, onSave, onClose, }) => { const { t } = useTranslation() - const locale = useGetLanguage() as LocaleKey + const docLanguage = useGetDocLanguage() const [currentTab, setCurrentTab] = useState(SchemaView.VisualEditor) const [jsonSchema, setJsonSchema] = useState(defaultSchema || DEFAULT_SCHEMA) const [json, setJson] = useState(JSON.stringify(jsonSchema, null, 2)) @@ -260,7 +252,7 @@ const JsonSchemaConfig: FC = ({
diff --git a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/schema-editor.tsx b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/schema-editor.tsx index e78b9224b2..05a429ff72 100644 --- a/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/schema-editor.tsx +++ b/web/app/components/workflow/nodes/llm/components/json-schema-config-modal/schema-editor.tsx @@ -12,7 +12,7 @@ const SchemaEditor: FC = ({ }) => { return ( Date: Fri, 30 May 2025 14:10:09 +0800 Subject: [PATCH 15/73] fix: drop some type fixme (#20344) --- api/core/model_runtime/utils/encoders.py | 23 ++++++------ .../rag/datasource/vdb/baidu/baidu_vector.py | 1 - .../vdb/tidb_on_qdrant/tidb_service.py | 2 +- api/core/tools/entities/tool_entities.py | 1 - api/core/tools/utils/message_transformer.py | 1 - .../parameter_extractor_node.py | 1 - api/factories/variable_factory.py | 4 +-- api/schedule/clean_messages.py | 3 +- api/services/ops_service.py | 16 ++++----- api/services/website_service.py | 36 ++++++++++--------- 10 files changed, 43 insertions(+), 45 deletions(-) diff --git a/api/core/model_runtime/utils/encoders.py b/api/core/model_runtime/utils/encoders.py index 03e3506271..a5c11aeeba 100644 --- a/api/core/model_runtime/utils/encoders.py +++ b/api/core/model_runtime/utils/encoders.py @@ -129,17 +129,18 @@ def jsonable_encoder( sqlalchemy_safe=sqlalchemy_safe, ) if dataclasses.is_dataclass(obj): - # FIXME: mypy error, try to fix it instead of using type: ignore - obj_dict = dataclasses.asdict(obj) # type: ignore - return jsonable_encoder( - obj_dict, - by_alias=by_alias, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - custom_encoder=custom_encoder, - sqlalchemy_safe=sqlalchemy_safe, - ) + # Ensure obj is a dataclass instance, not a dataclass type + if not isinstance(obj, type): + obj_dict = dataclasses.asdict(obj) + return jsonable_encoder( + obj_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + custom_encoder=custom_encoder, + sqlalchemy_safe=sqlalchemy_safe, + ) if isinstance(obj, Enum): return obj.value if isinstance(obj, PurePath): diff --git a/api/core/rag/datasource/vdb/baidu/baidu_vector.py b/api/core/rag/datasource/vdb/baidu/baidu_vector.py index 86f1f5bfe4..db7ffc9c4f 100644 --- a/api/core/rag/datasource/vdb/baidu/baidu_vector.py +++ b/api/core/rag/datasource/vdb/baidu/baidu_vector.py @@ -85,7 +85,6 @@ class BaiduVector(BaseVector): end = min(start + batch_size, total_count) rows = [] assert len(metadatas) == total_count, "metadatas length should be equal to total_count" - # FIXME do you need this assert? for i in range(start, end, 1): row = Row( id=metadatas[i].get("doc_id", str(uuid.uuid4())), diff --git a/api/core/rag/datasource/vdb/tidb_on_qdrant/tidb_service.py b/api/core/rag/datasource/vdb/tidb_on_qdrant/tidb_service.py index 3958280bd5..184b5f2142 100644 --- a/api/core/rag/datasource/vdb/tidb_on_qdrant/tidb_service.py +++ b/api/core/rag/datasource/vdb/tidb_on_qdrant/tidb_service.py @@ -245,4 +245,4 @@ class TidbService: return cluster_infos else: response.raise_for_status() - return [] # FIXME for mypy, This line will not be reached as raise_for_status() will raise an exception + return [] diff --git a/api/core/tools/entities/tool_entities.py b/api/core/tools/entities/tool_entities.py index 37375f4a71..03047c0545 100644 --- a/api/core/tools/entities/tool_entities.py +++ b/api/core/tools/entities/tool_entities.py @@ -279,7 +279,6 @@ class ToolParameter(PluginParameter): :param options: the options of the parameter """ # convert options to ToolParameterOption - # FIXME fix the type error if options: option_objs = [ PluginParameterOption(value=option, label=I18nObject(en_US=option, zh_Hans=option)) diff --git a/api/core/tools/utils/message_transformer.py b/api/core/tools/utils/message_transformer.py index 257d96133e..80e8b54343 100644 --- a/api/core/tools/utils/message_transformer.py +++ b/api/core/tools/utils/message_transformer.py @@ -66,7 +66,6 @@ class ToolFileMessageTransformer: if not isinstance(message.message, ToolInvokeMessage.BlobMessage): raise ValueError("unexpected message type") - # FIXME: should do a type check here. assert isinstance(message.message.blob, bytes) tool_file_manager = ToolFileManager() file = tool_file_manager.create_file_by_raw( diff --git a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py index 3d13cf7ecd..ea4070e224 100644 --- a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py +++ b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py @@ -816,7 +816,6 @@ class ParameterExtractorNode(LLMNode): :param node_data: node data :return: """ - # FIXME: fix the type error later variable_mapping: dict[str, Sequence[str]] = {"query": node_data.query} if node_data.instruction: diff --git a/api/factories/variable_factory.py b/api/factories/variable_factory.py index bbca8448ec..fa8a90e79f 100644 --- a/api/factories/variable_factory.py +++ b/api/factories/variable_factory.py @@ -84,8 +84,8 @@ def _build_variable_from_mapping(*, mapping: Mapping[str, Any], selector: Sequen raise VariableError("missing value type") if (value := mapping.get("value")) is None: raise VariableError("missing value") - # FIXME: using Any here, fix it later - result: Any + + result: Variable match value_type: case SegmentType.STRING: result = StringVariable.model_validate(mapping) diff --git a/api/schedule/clean_messages.py b/api/schedule/clean_messages.py index f41f5264c7..d02bc81f33 100644 --- a/api/schedule/clean_messages.py +++ b/api/schedule/clean_messages.py @@ -34,9 +34,8 @@ def clean_messages(): while True: try: # Main query with join and filter - # FIXME:for mypy no paginate method error messages = ( - db.session.query(Message) # type: ignore + db.session.query(Message) .filter(Message.created_at < plan_sandbox_clean_message_day) .order_by(Message.created_at.desc()) .limit(100) diff --git a/api/services/ops_service.py b/api/services/ops_service.py index a9c2b28476..792f50703e 100644 --- a/api/services/ops_service.py +++ b/api/services/ops_service.py @@ -1,5 +1,6 @@ -from typing import Optional +from typing import Any, Optional +from core.ops.entities.config_entity import BaseTracingConfig from core.ops.ops_trace_manager import OpsTraceManager, provider_config_map from extensions.ext_database import db from models.model import App, TraceAppConfig @@ -92,13 +93,12 @@ class OpsService: except KeyError: return {"error": f"Invalid tracing provider: {tracing_provider}"} - config_class, other_keys = ( - provider_config_map[tracing_provider]["config_class"], - provider_config_map[tracing_provider]["other_keys"], - ) - # FIXME: ignore type error - default_config_instance = config_class(**tracing_config) # type: ignore - for key in other_keys: # type: ignore + provider_config: dict[str, Any] = provider_config_map[tracing_provider] + config_class: type[BaseTracingConfig] = provider_config["config_class"] + other_keys: list[str] = provider_config["other_keys"] + + default_config_instance: BaseTracingConfig = config_class(**tracing_config) + for key in other_keys: if key in tracing_config and tracing_config[key] == "": tracing_config[key] = getattr(default_config_instance, key, None) diff --git a/api/services/website_service.py b/api/services/website_service.py index 3913dc2efe..6720932a3a 100644 --- a/api/services/website_service.py +++ b/api/services/website_service.py @@ -173,26 +173,27 @@ class WebsiteService: return crawl_status_data @classmethod - def get_crawl_url_data(cls, job_id: str, provider: str, url: str, tenant_id: str) -> dict[Any, Any] | None: + def get_crawl_url_data(cls, job_id: str, provider: str, url: str, tenant_id: str) -> dict[str, Any] | None: credentials = ApiKeyAuthService.get_auth_credentials(tenant_id, "website", provider) # decrypt api_key api_key = encrypter.decrypt_token(tenant_id=tenant_id, token=credentials.get("config").get("api_key")) - # FIXME data is redefine too many times here, use Any to ease the type checking, fix it later - data: Any + if provider == "firecrawl": + crawl_data: list[dict[str, Any]] | None = None file_key = "website_files/" + job_id + ".txt" if storage.exists(file_key): - d = storage.load_once(file_key) - if d: - data = json.loads(d.decode("utf-8")) + stored_data = storage.load_once(file_key) + if stored_data: + crawl_data = json.loads(stored_data.decode("utf-8")) else: firecrawl_app = FirecrawlApp(api_key=api_key, base_url=credentials.get("config").get("base_url", None)) result = firecrawl_app.check_crawl_status(job_id) if result.get("status") != "completed": raise ValueError("Crawl job is not completed") - data = result.get("data") - if data: - for item in data: + crawl_data = result.get("data") + + if crawl_data: + for item in crawl_data: if item.get("source_url") == url: return dict(item) return None @@ -211,23 +212,24 @@ class WebsiteService: raise ValueError("Failed to crawl") return dict(response.json().get("data", {})) else: - api_key = encrypter.decrypt_token(tenant_id=tenant_id, token=credentials.get("config").get("api_key")) - response = requests.post( + # Get crawl status first + status_response = requests.post( "https://adaptivecrawlstatus-kir3wx7b3a-uc.a.run.app", headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}, json={"taskId": job_id}, ) - data = response.json().get("data", {}) - if data.get("status") != "completed": + status_data = status_response.json().get("data", {}) + if status_data.get("status") != "completed": raise ValueError("Crawl job is not completed") - response = requests.post( + # Get processed data + data_response = requests.post( "https://adaptivecrawlstatus-kir3wx7b3a-uc.a.run.app", headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}, - json={"taskId": job_id, "urls": list(data.get("processed", {}).keys())}, + json={"taskId": job_id, "urls": list(status_data.get("processed", {}).keys())}, ) - data = response.json().get("data", {}) - for item in data.get("processed", {}).values(): + processed_data = data_response.json().get("data", {}) + for item in processed_data.get("processed", {}).values(): if item.get("data", {}).get("url") == url: return dict(item.get("data", {})) return None From a6ea15e63cd9d9520f94cb085f8dc6fc28ca6297 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 14:36:44 +0800 Subject: [PATCH 16/73] Refactor/message cycle manage and knowledge retrieval (#20460) Signed-off-by: -LAN- --- .../advanced_chat/generate_task_pipeline.py | 44 +++++------ .../apps/workflow/generate_task_pipeline.py | 4 - api/core/app/entities/queue_entities.py | 5 +- api/core/app/entities/task_entities.py | 23 +++++- .../easy_ui_based_generate_task_pipeline.py | 45 ++++++------ ...cle_manage.py => message_cycle_manager.py} | 29 +++++--- .../index_tool_callback_handler.py | 5 +- api/core/rag/entities/citation_metadata.py | 23 ++++++ api/core/rag/retrieval/dataset_retrieval.py | 63 ++++++++-------- .../dataset_multi_retriever_tool.py | 39 +++++----- .../dataset_retriever_tool.py | 73 ++++++++++--------- .../workflow/graph_engine/entities/event.py | 5 +- api/core/workflow/nodes/event/event.py | 4 +- api/core/workflow/nodes/llm/node.py | 41 ++++++----- 14 files changed, 222 insertions(+), 181 deletions(-) rename api/core/app/task_pipeline/{message_cycle_manage.py => message_cycle_manager.py} (85%) create mode 100644 api/core/rag/entities/citation_metadata.py diff --git a/api/core/app/apps/advanced_chat/generate_task_pipeline.py b/api/core/app/apps/advanced_chat/generate_task_pipeline.py index 112e178b82..8c5645bbb7 100644 --- a/api/core/app/apps/advanced_chat/generate_task_pipeline.py +++ b/api/core/app/apps/advanced_chat/generate_task_pipeline.py @@ -1,4 +1,3 @@ -import json import logging import time from collections.abc import Generator, Mapping @@ -57,10 +56,9 @@ from core.app.entities.task_entities import ( WorkflowTaskState, ) from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline -from core.app.task_pipeline.message_cycle_manage import MessageCycleManage +from core.app.task_pipeline.message_cycle_manager import MessageCycleManager from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk from core.model_runtime.entities.llm_entities import LLMUsage -from core.model_runtime.utils.encoders import jsonable_encoder from core.ops.ops_trace_manager import TraceQueueManager from core.workflow.entities.workflow_execution import WorkflowExecutionStatus, WorkflowType from core.workflow.enums import SystemVariableKey @@ -141,7 +139,7 @@ class AdvancedChatAppGenerateTaskPipeline: ) self._task_state = WorkflowTaskState() - self._message_cycle_manager = MessageCycleManage( + self._message_cycle_manager = MessageCycleManager( application_generate_entity=application_generate_entity, task_state=self._task_state ) @@ -162,7 +160,7 @@ class AdvancedChatAppGenerateTaskPipeline: :return: """ # start generate conversation name thread - self._conversation_name_generate_thread = self._message_cycle_manager._generate_conversation_name( + self._conversation_name_generate_thread = self._message_cycle_manager.generate_conversation_name( conversation_id=self._conversation_id, query=self._application_generate_entity.query ) @@ -605,22 +603,18 @@ class AdvancedChatAppGenerateTaskPipeline: yield self._message_end_to_stream_response() break elif isinstance(event, QueueRetrieverResourcesEvent): - self._message_cycle_manager._handle_retriever_resources(event) + self._message_cycle_manager.handle_retriever_resources(event) with Session(db.engine, expire_on_commit=False) as session: message = self._get_message(session=session) - message.message_metadata = ( - json.dumps(jsonable_encoder(self._task_state.metadata)) if self._task_state.metadata else None - ) + message.message_metadata = self._task_state.metadata.model_dump_json() session.commit() elif isinstance(event, QueueAnnotationReplyEvent): - self._message_cycle_manager._handle_annotation_reply(event) + self._message_cycle_manager.handle_annotation_reply(event) with Session(db.engine, expire_on_commit=False) as session: message = self._get_message(session=session) - message.message_metadata = ( - json.dumps(jsonable_encoder(self._task_state.metadata)) if self._task_state.metadata else None - ) + message.message_metadata = self._task_state.metadata.model_dump_json() session.commit() elif isinstance(event, QueueTextChunkEvent): delta_text = event.text @@ -637,12 +631,12 @@ class AdvancedChatAppGenerateTaskPipeline: tts_publisher.publish(queue_message) self._task_state.answer += delta_text - yield self._message_cycle_manager._message_to_stream_response( + yield self._message_cycle_manager.message_to_stream_response( answer=delta_text, message_id=self._message_id, from_variable_selector=event.from_variable_selector ) elif isinstance(event, QueueMessageReplaceEvent): # published by moderation - yield self._message_cycle_manager._message_replace_to_stream_response( + yield self._message_cycle_manager.message_replace_to_stream_response( answer=event.text, reason=event.reason ) elif isinstance(event, QueueAdvancedChatMessageEndEvent): @@ -654,7 +648,7 @@ class AdvancedChatAppGenerateTaskPipeline: ) if output_moderation_answer: self._task_state.answer = output_moderation_answer - yield self._message_cycle_manager._message_replace_to_stream_response( + yield self._message_cycle_manager.message_replace_to_stream_response( answer=output_moderation_answer, reason=QueueMessageReplaceEvent.MessageReplaceReason.OUTPUT_MODERATION, ) @@ -683,9 +677,7 @@ class AdvancedChatAppGenerateTaskPipeline: message = self._get_message(session=session) message.answer = self._task_state.answer message.provider_response_latency = time.perf_counter() - self._base_task_pipeline._start_at - message.message_metadata = ( - json.dumps(jsonable_encoder(self._task_state.metadata)) if self._task_state.metadata else None - ) + message.message_metadata = self._task_state.metadata.model_dump_json() message_files = [ MessageFile( message_id=message.id, @@ -713,9 +705,9 @@ class AdvancedChatAppGenerateTaskPipeline: message.answer_price_unit = usage.completion_price_unit message.total_price = usage.total_price message.currency = usage.currency - self._task_state.metadata["usage"] = jsonable_encoder(usage) + self._task_state.metadata.usage = usage else: - self._task_state.metadata["usage"] = jsonable_encoder(LLMUsage.empty_usage()) + self._task_state.metadata.usage = LLMUsage.empty_usage() message_was_created.send( message, application_generate_entity=self._application_generate_entity, @@ -726,18 +718,16 @@ class AdvancedChatAppGenerateTaskPipeline: Message end to stream response. :return: """ - extras = {} - if self._task_state.metadata: - extras["metadata"] = self._task_state.metadata.copy() + extras = self._task_state.metadata.model_dump() - if "annotation_reply" in extras["metadata"]: - del extras["metadata"]["annotation_reply"] + if self._task_state.metadata.annotation_reply: + del extras["annotation_reply"] return MessageEndStreamResponse( task_id=self._application_generate_entity.task_id, id=self._message_id, files=self._recorded_files, - metadata=extras.get("metadata", {}), + metadata=extras, ) def _handle_output_moderation_chunk(self, text: str) -> bool: diff --git a/api/core/app/apps/workflow/generate_task_pipeline.py b/api/core/app/apps/workflow/generate_task_pipeline.py index fb0ea80a3a..1734dbb598 100644 --- a/api/core/app/apps/workflow/generate_task_pipeline.py +++ b/api/core/app/apps/workflow/generate_task_pipeline.py @@ -50,7 +50,6 @@ from core.app.entities.task_entities import ( WorkflowAppStreamResponse, WorkflowFinishStreamResponse, WorkflowStartStreamResponse, - WorkflowTaskState, ) from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk @@ -130,9 +129,7 @@ class WorkflowAppGenerateTaskPipeline: ) self._application_generate_entity = application_generate_entity - self._workflow_id = workflow.id self._workflow_features_dict = workflow.features_dict - self._task_state = WorkflowTaskState() self._workflow_run_id = "" def process(self) -> Union[WorkflowAppBlockingResponse, Generator[WorkflowAppStreamResponse, None, None]]: @@ -543,7 +540,6 @@ class WorkflowAppGenerateTaskPipeline: if tts_publisher: tts_publisher.publish(queue_message) - self._task_state.answer += delta_text yield self._text_chunk_to_stream_response( delta_text, from_variable_selector=event.from_variable_selector ) diff --git a/api/core/app/entities/queue_entities.py b/api/core/app/entities/queue_entities.py index bc8573013a..42e6a1519c 100644 --- a/api/core/app/entities/queue_entities.py +++ b/api/core/app/entities/queue_entities.py @@ -1,4 +1,4 @@ -from collections.abc import Mapping +from collections.abc import Mapping, Sequence from datetime import datetime from enum import Enum, StrEnum from typing import Any, Optional @@ -6,6 +6,7 @@ from typing import Any, Optional from pydantic import BaseModel from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.workflow.entities.node_entities import AgentNodeStrategyInit from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState @@ -283,7 +284,7 @@ class QueueRetrieverResourcesEvent(AppQueueEvent): """ event: QueueEvent = QueueEvent.RETRIEVER_RESOURCES - retriever_resources: list[dict] + retriever_resources: Sequence[RetrievalSourceMetadata] in_iteration_id: Optional[str] = None """iteration id if node is in iteration""" in_loop_id: Optional[str] = None diff --git a/api/core/app/entities/task_entities.py b/api/core/app/entities/task_entities.py index 70748b085d..25c889e922 100644 --- a/api/core/app/entities/task_entities.py +++ b/api/core/app/entities/task_entities.py @@ -2,20 +2,37 @@ from collections.abc import Mapping, Sequence from enum import Enum from typing import Any, Optional -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field -from core.model_runtime.entities.llm_entities import LLMResult +from core.model_runtime.entities.llm_entities import LLMResult, LLMUsage from core.model_runtime.utils.encoders import jsonable_encoder +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.workflow.entities.node_entities import AgentNodeStrategyInit from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey, WorkflowNodeExecutionStatus +class AnnotationReplyAccount(BaseModel): + id: str + name: str + + +class AnnotationReply(BaseModel): + id: str + account: AnnotationReplyAccount + + +class TaskStateMetadata(BaseModel): + annotation_reply: AnnotationReply | None = None + retriever_resources: Sequence[RetrievalSourceMetadata] = Field(default_factory=list) + usage: LLMUsage | None = None + + class TaskState(BaseModel): """ TaskState entity """ - metadata: dict = {} + metadata: TaskStateMetadata = Field(default_factory=TaskStateMetadata) class EasyUITaskState(TaskState): diff --git a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py index 6c768fd86c..1ea50a5778 100644 --- a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py +++ b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py @@ -1,4 +1,3 @@ -import json import logging import time from collections.abc import Generator @@ -43,7 +42,7 @@ from core.app.entities.task_entities import ( StreamResponse, ) from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTaskPipeline -from core.app.task_pipeline.message_cycle_manage import MessageCycleManage +from core.app.task_pipeline.message_cycle_manager import MessageCycleManager from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk from core.model_manager import ModelInstance from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk, LLMResultChunkDelta, LLMUsage @@ -51,7 +50,6 @@ from core.model_runtime.entities.message_entities import ( AssistantPromptMessage, ) from core.model_runtime.model_providers.__base.large_language_model import LargeLanguageModel -from core.model_runtime.utils.encoders import jsonable_encoder from core.ops.entities.trace_entity import TraceTaskName from core.ops.ops_trace_manager import TraceQueueManager, TraceTask from core.prompt.utils.prompt_message_util import PromptMessageUtil @@ -63,7 +61,7 @@ from models.model import AppMode, Conversation, Message, MessageAgentThought logger = logging.getLogger(__name__) -class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleManage): +class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline): """ EasyUIBasedGenerateTaskPipeline is a class that generate stream output and state management for Application. """ @@ -104,6 +102,11 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan ) ) + self._message_cycle_manager = MessageCycleManager( + application_generate_entity=application_generate_entity, + task_state=self._task_state, + ) + self._conversation_name_generate_thread: Optional[Thread] = None def process( @@ -115,7 +118,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan ]: if self._application_generate_entity.app_config.app_mode != AppMode.COMPLETION: # start generate conversation name thread - self._conversation_name_generate_thread = self._generate_conversation_name( + self._conversation_name_generate_thread = self._message_cycle_manager.generate_conversation_name( conversation_id=self._conversation_id, query=self._application_generate_entity.query or "" ) @@ -136,9 +139,9 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan if isinstance(stream_response, ErrorStreamResponse): raise stream_response.err elif isinstance(stream_response, MessageEndStreamResponse): - extras = {"usage": jsonable_encoder(self._task_state.llm_result.usage)} + extras = {"usage": self._task_state.llm_result.usage.model_dump()} if self._task_state.metadata: - extras["metadata"] = self._task_state.metadata + extras["metadata"] = self._task_state.metadata.model_dump() response: Union[ChatbotAppBlockingResponse, CompletionAppBlockingResponse] if self._conversation_mode == AppMode.COMPLETION.value: response = CompletionAppBlockingResponse( @@ -277,7 +280,9 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan ) if output_moderation_answer: self._task_state.llm_result.message.content = output_moderation_answer - yield self._message_replace_to_stream_response(answer=output_moderation_answer) + yield self._message_cycle_manager.message_replace_to_stream_response( + answer=output_moderation_answer + ) with Session(db.engine) as session: # Save message @@ -286,9 +291,9 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan message_end_resp = self._message_end_to_stream_response() yield message_end_resp elif isinstance(event, QueueRetrieverResourcesEvent): - self._handle_retriever_resources(event) + self._message_cycle_manager.handle_retriever_resources(event) elif isinstance(event, QueueAnnotationReplyEvent): - annotation = self._handle_annotation_reply(event) + annotation = self._message_cycle_manager.handle_annotation_reply(event) if annotation: self._task_state.llm_result.message.content = annotation.content elif isinstance(event, QueueAgentThoughtEvent): @@ -296,7 +301,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan if agent_thought_response is not None: yield agent_thought_response elif isinstance(event, QueueMessageFileEvent): - response = self._message_file_to_stream_response(event) + response = self._message_cycle_manager.message_file_to_stream_response(event) if response: yield response elif isinstance(event, QueueLLMChunkEvent | QueueAgentMessageEvent): @@ -318,7 +323,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan self._task_state.llm_result.message.content = current_content if isinstance(event, QueueLLMChunkEvent): - yield self._message_to_stream_response( + yield self._message_cycle_manager.message_to_stream_response( answer=cast(str, delta_text), message_id=self._message_id, ) @@ -328,7 +333,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan message_id=self._message_id, ) elif isinstance(event, QueueMessageReplaceEvent): - yield self._message_replace_to_stream_response(answer=event.text) + yield self._message_cycle_manager.message_replace_to_stream_response(answer=event.text) elif isinstance(event, QueuePingEvent): yield self._ping_stream_response() else: @@ -372,9 +377,7 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan message.provider_response_latency = time.perf_counter() - self._start_at message.total_price = usage.total_price message.currency = usage.currency - message.message_metadata = ( - json.dumps(jsonable_encoder(self._task_state.metadata)) if self._task_state.metadata else None - ) + message.message_metadata = self._task_state.metadata.model_dump_json() if trace_manager: trace_manager.add_trace_task( @@ -423,16 +426,12 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline, MessageCycleMan Message end to stream response. :return: """ - self._task_state.metadata["usage"] = jsonable_encoder(self._task_state.llm_result.usage) - - extras = {} - if self._task_state.metadata: - extras["metadata"] = self._task_state.metadata - + self._task_state.metadata.usage = self._task_state.llm_result.usage + metadata_dict = self._task_state.metadata.model_dump() return MessageEndStreamResponse( task_id=self._application_generate_entity.task_id, id=self._message_id, - metadata=extras.get("metadata", {}), + metadata=metadata_dict, ) def _agent_message_to_stream_response(self, answer: str, message_id: str) -> AgentMessageStreamResponse: diff --git a/api/core/app/task_pipeline/message_cycle_manage.py b/api/core/app/task_pipeline/message_cycle_manager.py similarity index 85% rename from api/core/app/task_pipeline/message_cycle_manage.py rename to api/core/app/task_pipeline/message_cycle_manager.py index a6d826f08b..2343081eaf 100644 --- a/api/core/app/task_pipeline/message_cycle_manage.py +++ b/api/core/app/task_pipeline/message_cycle_manager.py @@ -17,6 +17,8 @@ from core.app.entities.queue_entities import ( QueueRetrieverResourcesEvent, ) from core.app.entities.task_entities import ( + AnnotationReply, + AnnotationReplyAccount, EasyUITaskState, MessageFileStreamResponse, MessageReplaceStreamResponse, @@ -30,7 +32,7 @@ from models.model import AppMode, Conversation, MessageAnnotation, MessageFile from services.annotation_service import AppAnnotationService -class MessageCycleManage: +class MessageCycleManager: def __init__( self, *, @@ -45,7 +47,7 @@ class MessageCycleManage: self._application_generate_entity = application_generate_entity self._task_state = task_state - def _generate_conversation_name(self, *, conversation_id: str, query: str) -> Optional[Thread]: + def generate_conversation_name(self, *, conversation_id: str, query: str) -> Optional[Thread]: """ Generate conversation name. :param conversation_id: conversation id @@ -102,7 +104,7 @@ class MessageCycleManage: db.session.commit() db.session.close() - def _handle_annotation_reply(self, event: QueueAnnotationReplyEvent) -> Optional[MessageAnnotation]: + def handle_annotation_reply(self, event: QueueAnnotationReplyEvent) -> Optional[MessageAnnotation]: """ Handle annotation reply. :param event: event @@ -111,25 +113,28 @@ class MessageCycleManage: annotation = AppAnnotationService.get_annotation_by_id(event.message_annotation_id) if annotation: account = annotation.account - self._task_state.metadata["annotation_reply"] = { - "id": annotation.id, - "account": {"id": annotation.account_id, "name": account.name if account else "Dify user"}, - } + self._task_state.metadata.annotation_reply = AnnotationReply( + id=annotation.id, + account=AnnotationReplyAccount( + id=annotation.account_id, + name=account.name if account else "Dify user", + ), + ) return annotation return None - def _handle_retriever_resources(self, event: QueueRetrieverResourcesEvent) -> None: + def handle_retriever_resources(self, event: QueueRetrieverResourcesEvent) -> None: """ Handle retriever resources. :param event: event :return: """ if self._application_generate_entity.app_config.additional_features.show_retrieve_source: - self._task_state.metadata["retriever_resources"] = event.retriever_resources + self._task_state.metadata.retriever_resources = event.retriever_resources - def _message_file_to_stream_response(self, event: QueueMessageFileEvent) -> Optional[MessageFileStreamResponse]: + def message_file_to_stream_response(self, event: QueueMessageFileEvent) -> Optional[MessageFileStreamResponse]: """ Message file to stream response. :param event: event @@ -166,7 +171,7 @@ class MessageCycleManage: return None - def _message_to_stream_response( + def message_to_stream_response( self, answer: str, message_id: str, from_variable_selector: Optional[list[str]] = None ) -> MessageStreamResponse: """ @@ -182,7 +187,7 @@ class MessageCycleManage: from_variable_selector=from_variable_selector, ) - def _message_replace_to_stream_response(self, answer: str, reason: str = "") -> MessageReplaceStreamResponse: + def message_replace_to_stream_response(self, answer: str, reason: str = "") -> MessageReplaceStreamResponse: """ Message replace to stream response. :param answer: answer diff --git a/api/core/callback_handler/index_tool_callback_handler.py b/api/core/callback_handler/index_tool_callback_handler.py index 13c22213c4..a3a7b4b812 100644 --- a/api/core/callback_handler/index_tool_callback_handler.py +++ b/api/core/callback_handler/index_tool_callback_handler.py @@ -1,8 +1,10 @@ import logging +from collections.abc import Sequence from core.app.apps.base_app_queue_manager import AppQueueManager, PublishFrom from core.app.entities.app_invoke_entities import InvokeFrom from core.app.entities.queue_entities import QueueRetrieverResourcesEvent +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.rag.index_processor.constant.index_type import IndexType from core.rag.models.document import Document from extensions.ext_database import db @@ -85,7 +87,8 @@ class DatasetIndexToolCallbackHandler: db.session.commit() - def return_retriever_resource_info(self, resource: list): + # TODO(-LAN-): Improve type check + def return_retriever_resource_info(self, resource: Sequence[RetrievalSourceMetadata]): """Handle return_retriever_resource_info.""" self._queue_manager.publish( QueueRetrieverResourcesEvent(retriever_resources=resource), PublishFrom.APPLICATION_MANAGER diff --git a/api/core/rag/entities/citation_metadata.py b/api/core/rag/entities/citation_metadata.py new file mode 100644 index 0000000000..00120425c9 --- /dev/null +++ b/api/core/rag/entities/citation_metadata.py @@ -0,0 +1,23 @@ +from typing import Any, Optional + +from pydantic import BaseModel + + +class RetrievalSourceMetadata(BaseModel): + position: Optional[int] = None + dataset_id: Optional[str] = None + dataset_name: Optional[str] = None + document_id: Optional[str] = None + document_name: Optional[str] = None + data_source_type: Optional[str] = None + segment_id: Optional[str] = None + retriever_from: Optional[str] = None + score: Optional[float] = None + hit_count: Optional[int] = None + word_count: Optional[int] = None + segment_position: Optional[int] = None + index_node_hash: Optional[str] = None + content: Optional[str] = None + page: Optional[int] = None + doc_metadata: Optional[dict[str, Any]] = None + title: Optional[str] = None diff --git a/api/core/rag/retrieval/dataset_retrieval.py b/api/core/rag/retrieval/dataset_retrieval.py index c4adf6de4d..f668148428 100644 --- a/api/core/rag/retrieval/dataset_retrieval.py +++ b/api/core/rag/retrieval/dataset_retrieval.py @@ -35,6 +35,7 @@ from core.prompt.simple_prompt_transform import ModelMode from core.rag.data_post_processor.data_post_processor import DataPostProcessor from core.rag.datasource.keyword.jieba.jieba_keyword_table_handler import JiebaKeywordTableHandler from core.rag.datasource.retrieval_service import RetrievalService +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.rag.entities.context_entities import DocumentContext from core.rag.entities.metadata_entities import Condition, MetadataCondition from core.rag.index_processor.constant.index_type import IndexType @@ -198,21 +199,21 @@ class DatasetRetrieval: dify_documents = [item for item in all_documents if item.provider == "dify"] external_documents = [item for item in all_documents if item.provider == "external"] - document_context_list = [] - retrieval_resource_list = [] + document_context_list: list[DocumentContext] = [] + retrieval_resource_list: list[RetrievalSourceMetadata] = [] # deal with external documents for item in external_documents: document_context_list.append(DocumentContext(content=item.page_content, score=item.metadata.get("score"))) - source = { - "dataset_id": item.metadata.get("dataset_id"), - "dataset_name": item.metadata.get("dataset_name"), - "document_id": item.metadata.get("document_id") or item.metadata.get("title"), - "document_name": item.metadata.get("title"), - "data_source_type": "external", - "retriever_from": invoke_from.to_source(), - "score": item.metadata.get("score"), - "content": item.page_content, - } + source = RetrievalSourceMetadata( + dataset_id=item.metadata.get("dataset_id"), + dataset_name=item.metadata.get("dataset_name"), + document_id=item.metadata.get("document_id") or item.metadata.get("title"), + document_name=item.metadata.get("title"), + data_source_type="external", + retriever_from=invoke_from.to_source(), + score=item.metadata.get("score"), + content=item.page_content, + ) retrieval_resource_list.append(source) # deal with dify documents if dify_documents: @@ -248,32 +249,32 @@ class DatasetRetrieval: .first() ) if dataset and document: - source = { - "dataset_id": dataset.id, - "dataset_name": dataset.name, - "document_id": document.id, - "document_name": document.name, - "data_source_type": document.data_source_type, - "segment_id": segment.id, - "retriever_from": invoke_from.to_source(), - "score": record.score or 0.0, - "doc_metadata": document.doc_metadata, - } + source = RetrievalSourceMetadata( + dataset_id=dataset.id, + dataset_name=dataset.name, + document_id=document.id, + document_name=document.name, + data_source_type=document.data_source_type, + segment_id=segment.id, + retriever_from=invoke_from.to_source(), + score=record.score or 0.0, + doc_metadata=document.doc_metadata, + ) if invoke_from.to_source() == "dev": - source["hit_count"] = segment.hit_count - source["word_count"] = segment.word_count - source["segment_position"] = segment.position - source["index_node_hash"] = segment.index_node_hash + source.hit_count = segment.hit_count + source.word_count = segment.word_count + source.segment_position = segment.position + source.index_node_hash = segment.index_node_hash if segment.answer: - source["content"] = f"question:{segment.content} \nanswer:{segment.answer}" + source.content = f"question:{segment.content} \nanswer:{segment.answer}" else: - source["content"] = segment.content + source.content = segment.content retrieval_resource_list.append(source) if hit_callback and retrieval_resource_list: - retrieval_resource_list = sorted(retrieval_resource_list, key=lambda x: x.get("score") or 0.0, reverse=True) + retrieval_resource_list = sorted(retrieval_resource_list, key=lambda x: x.score or 0.0, reverse=True) for position, item in enumerate(retrieval_resource_list, start=1): - item["position"] = position + item.position = position hit_callback.return_retriever_resource_info(retrieval_resource_list) if document_context_list: document_context_list = sorted(document_context_list, key=lambda x: x.score or 0.0, reverse=True) diff --git a/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py b/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py index 04437ea6d8..93d3fcc49d 100644 --- a/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py +++ b/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py @@ -8,6 +8,7 @@ from core.callback_handler.index_tool_callback_handler import DatasetIndexToolCa from core.model_manager import ModelManager from core.model_runtime.entities.model_entities import ModelType from core.rag.datasource.retrieval_service import RetrievalService +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.rag.models.document import Document as RagDocument from core.rag.rerank.rerank_model import RerankModelRunner from core.rag.retrieval.retrieval_methods import RetrievalMethod @@ -107,7 +108,7 @@ class DatasetMultiRetrieverTool(DatasetRetrieverBaseTool): else: document_context_list.append(segment.get_sign_content()) if self.return_resource: - context_list = [] + context_list: list[RetrievalSourceMetadata] = [] resource_number = 1 for segment in sorted_segments: dataset = db.session.query(Dataset).filter_by(id=segment.dataset_id).first() @@ -121,28 +122,28 @@ class DatasetMultiRetrieverTool(DatasetRetrieverBaseTool): .first() ) if dataset and document: - source = { - "position": resource_number, - "dataset_id": dataset.id, - "dataset_name": dataset.name, - "document_id": document.id, - "document_name": document.name, - "data_source_type": document.data_source_type, - "segment_id": segment.id, - "retriever_from": self.retriever_from, - "score": document_score_list.get(segment.index_node_id, None), - "doc_metadata": document.doc_metadata, - } + source = RetrievalSourceMetadata( + position=resource_number, + dataset_id=dataset.id, + dataset_name=dataset.name, + document_id=document.id, + document_name=document.name, + data_source_type=document.data_source_type, + segment_id=segment.id, + retriever_from=self.retriever_from, + score=document_score_list.get(segment.index_node_id, None), + doc_metadata=document.doc_metadata, + ) if self.retriever_from == "dev": - source["hit_count"] = segment.hit_count - source["word_count"] = segment.word_count - source["segment_position"] = segment.position - source["index_node_hash"] = segment.index_node_hash + source.hit_count = segment.hit_count + source.word_count = segment.word_count + source.segment_position = segment.position + source.index_node_hash = segment.index_node_hash if segment.answer: - source["content"] = f"question:{segment.content} \nanswer:{segment.answer}" + source.content = f"question:{segment.content} \nanswer:{segment.answer}" else: - source["content"] = segment.content + source.content = segment.content context_list.append(source) resource_number += 1 diff --git a/api/core/tools/utils/dataset_retriever/dataset_retriever_tool.py b/api/core/tools/utils/dataset_retriever/dataset_retriever_tool.py index 7b6882ed52..ff1d9021ce 100644 --- a/api/core/tools/utils/dataset_retriever/dataset_retriever_tool.py +++ b/api/core/tools/utils/dataset_retriever/dataset_retriever_tool.py @@ -4,6 +4,7 @@ from pydantic import BaseModel, Field from core.app.app_config.entities import DatasetRetrieveConfigEntity, ModelConfig from core.rag.datasource.retrieval_service import RetrievalService +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.rag.entities.context_entities import DocumentContext from core.rag.models.document import Document as RetrievalDocument from core.rag.retrieval.dataset_retrieval import DatasetRetrieval @@ -14,7 +15,7 @@ from models.dataset import Dataset from models.dataset import Document as DatasetDocument from services.external_knowledge_service import ExternalDatasetService -default_retrieval_model = { +default_retrieval_model: dict[str, Any] = { "search_method": RetrievalMethod.SEMANTIC_SEARCH.value, "reranking_enable": False, "reranking_model": {"reranking_provider_name": "", "reranking_model_name": ""}, @@ -79,7 +80,7 @@ class DatasetRetrieverTool(DatasetRetrieverBaseTool): else: document_ids_filter = None if dataset.provider == "external": - results = [] + results: list[RetrievalDocument] = [] external_documents = ExternalDatasetService.fetch_external_knowledge_retrieval( tenant_id=dataset.tenant_id, dataset_id=dataset.id, @@ -100,21 +101,21 @@ class DatasetRetrieverTool(DatasetRetrieverBaseTool): document.metadata["dataset_name"] = dataset.name results.append(document) # deal with external documents - context_list = [] + context_list: list[RetrievalSourceMetadata] = [] for position, item in enumerate(results, start=1): if item.metadata is not None: - source = { - "position": position, - "dataset_id": item.metadata.get("dataset_id"), - "dataset_name": item.metadata.get("dataset_name"), - "document_id": item.metadata.get("document_id") or item.metadata.get("title"), - "document_name": item.metadata.get("title"), - "data_source_type": "external", - "retriever_from": self.retriever_from, - "score": item.metadata.get("score"), - "title": item.metadata.get("title"), - "content": item.page_content, - } + source = RetrievalSourceMetadata( + position=position, + dataset_id=item.metadata.get("dataset_id"), + dataset_name=item.metadata.get("dataset_name"), + document_id=item.metadata.get("document_id") or item.metadata.get("title"), + document_name=item.metadata.get("title"), + data_source_type="external", + retriever_from=self.retriever_from, + score=item.metadata.get("score"), + title=item.metadata.get("title"), + content=item.page_content, + ) context_list.append(source) for hit_callback in self.hit_callbacks: hit_callback.return_retriever_resource_info(context_list) @@ -125,7 +126,7 @@ class DatasetRetrieverTool(DatasetRetrieverBaseTool): return "" # get retrieval model , if the model is not setting , using default retrieval_model: dict[str, Any] = dataset.retrieval_model or default_retrieval_model - retrieval_resource_list = [] + retrieval_resource_list: list[RetrievalSourceMetadata] = [] if dataset.indexing_technique == "economy": # use keyword table query documents = RetrievalService.retrieve( @@ -163,7 +164,7 @@ class DatasetRetrieverTool(DatasetRetrieverBaseTool): for item in documents: if item.metadata is not None and item.metadata.get("score"): document_score_list[item.metadata["doc_id"]] = item.metadata["score"] - document_context_list = [] + document_context_list: list[DocumentContext] = [] records = RetrievalService.format_retrieval_documents(documents) if records: for record in records: @@ -197,37 +198,37 @@ class DatasetRetrieverTool(DatasetRetrieverBaseTool): .first() ) if dataset and document: - source = { - "dataset_id": dataset.id, - "dataset_name": dataset.name, - "document_id": document.id, # type: ignore - "document_name": document.name, # type: ignore - "data_source_type": document.data_source_type, # type: ignore - "segment_id": segment.id, - "retriever_from": self.retriever_from, - "score": record.score or 0.0, - "doc_metadata": document.doc_metadata, # type: ignore - } + source = RetrievalSourceMetadata( + dataset_id=dataset.id, + dataset_name=dataset.name, + document_id=document.id, # type: ignore + document_name=document.name, # type: ignore + data_source_type=document.data_source_type, # type: ignore + segment_id=segment.id, + retriever_from=self.retriever_from, + score=record.score or 0.0, + doc_metadata=document.doc_metadata, # type: ignore + ) if self.retriever_from == "dev": - source["hit_count"] = segment.hit_count - source["word_count"] = segment.word_count - source["segment_position"] = segment.position - source["index_node_hash"] = segment.index_node_hash + source.hit_count = segment.hit_count + source.word_count = segment.word_count + source.segment_position = segment.position + source.index_node_hash = segment.index_node_hash if segment.answer: - source["content"] = f"question:{segment.content} \nanswer:{segment.answer}" + source.content = f"question:{segment.content} \nanswer:{segment.answer}" else: - source["content"] = segment.content + source.content = segment.content retrieval_resource_list.append(source) if self.return_resource and retrieval_resource_list: retrieval_resource_list = sorted( retrieval_resource_list, - key=lambda x: x.get("score") or 0.0, + key=lambda x: x.score or 0.0, reverse=True, ) for position, item in enumerate(retrieval_resource_list, start=1): # type: ignore - item["position"] = position # type: ignore + item.position = position # type: ignore for hit_callback in self.hit_callbacks: hit_callback.return_retriever_resource_info(retrieval_resource_list) if document_context_list: diff --git a/api/core/workflow/graph_engine/entities/event.py b/api/core/workflow/graph_engine/entities/event.py index 689a07c4f6..9a4939502e 100644 --- a/api/core/workflow/graph_engine/entities/event.py +++ b/api/core/workflow/graph_engine/entities/event.py @@ -1,9 +1,10 @@ -from collections.abc import Mapping +from collections.abc import Mapping, Sequence from datetime import datetime from typing import Any, Optional from pydantic import BaseModel, Field +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.workflow.entities.node_entities import AgentNodeStrategyInit from core.workflow.graph_engine.entities.runtime_route_state import RouteNodeState from core.workflow.nodes import NodeType @@ -82,7 +83,7 @@ class NodeRunStreamChunkEvent(BaseNodeEvent): class NodeRunRetrieverResourceEvent(BaseNodeEvent): - retriever_resources: list[dict] = Field(..., description="retriever resources") + retriever_resources: Sequence[RetrievalSourceMetadata] = Field(..., description="retriever resources") context: str = Field(..., description="context") diff --git a/api/core/workflow/nodes/event/event.py b/api/core/workflow/nodes/event/event.py index f45919caf5..b72d111f49 100644 --- a/api/core/workflow/nodes/event/event.py +++ b/api/core/workflow/nodes/event/event.py @@ -1,8 +1,10 @@ +from collections.abc import Sequence from datetime import datetime from pydantic import BaseModel, Field from core.model_runtime.entities.llm_entities import LLMUsage +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.workflow.entities.node_entities import NodeRunResult from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionStatus @@ -17,7 +19,7 @@ class RunStreamChunkEvent(BaseModel): class RunRetrieverResourceEvent(BaseModel): - retriever_resources: list[dict] = Field(..., description="retriever resources") + retriever_resources: Sequence[RetrievalSourceMetadata] = Field(..., description="retriever resources") context: str = Field(..., description="context") diff --git a/api/core/workflow/nodes/llm/node.py b/api/core/workflow/nodes/llm/node.py index 38e4f7af01..0fd7c31ffb 100644 --- a/api/core/workflow/nodes/llm/node.py +++ b/api/core/workflow/nodes/llm/node.py @@ -43,6 +43,7 @@ from core.model_runtime.utils.encoders import jsonable_encoder from core.plugin.entities.plugin import ModelProviderID from core.prompt.entities.advanced_prompt_entities import CompletionModelPromptTemplate, MemoryConfig from core.prompt.utils.prompt_message_util import PromptMessageUtil +from core.rag.entities.citation_metadata import RetrievalSourceMetadata from core.variables import ( ArrayAnySegment, ArrayFileSegment, @@ -474,7 +475,7 @@ class LLMNode(BaseNode[LLMNodeData]): yield RunRetrieverResourceEvent(retriever_resources=[], context=context_value_variable.value) elif isinstance(context_value_variable, ArraySegment): context_str = "" - original_retriever_resource = [] + original_retriever_resource: list[RetrievalSourceMetadata] = [] for item in context_value_variable.value: if isinstance(item, str): context_str += item + "\n" @@ -492,7 +493,7 @@ class LLMNode(BaseNode[LLMNodeData]): retriever_resources=original_retriever_resource, context=context_str.strip() ) - def _convert_to_original_retriever_resource(self, context_dict: dict) -> Optional[dict]: + def _convert_to_original_retriever_resource(self, context_dict: dict): if ( "metadata" in context_dict and "_source" in context_dict["metadata"] @@ -500,24 +501,24 @@ class LLMNode(BaseNode[LLMNodeData]): ): metadata = context_dict.get("metadata", {}) - source = { - "position": metadata.get("position"), - "dataset_id": metadata.get("dataset_id"), - "dataset_name": metadata.get("dataset_name"), - "document_id": metadata.get("document_id"), - "document_name": metadata.get("document_name"), - "data_source_type": metadata.get("data_source_type"), - "segment_id": metadata.get("segment_id"), - "retriever_from": metadata.get("retriever_from"), - "score": metadata.get("score"), - "hit_count": metadata.get("segment_hit_count"), - "word_count": metadata.get("segment_word_count"), - "segment_position": metadata.get("segment_position"), - "index_node_hash": metadata.get("segment_index_node_hash"), - "content": context_dict.get("content"), - "page": metadata.get("page"), - "doc_metadata": metadata.get("doc_metadata"), - } + source = RetrievalSourceMetadata( + position=metadata.get("position"), + dataset_id=metadata.get("dataset_id"), + dataset_name=metadata.get("dataset_name"), + document_id=metadata.get("document_id"), + document_name=metadata.get("document_name"), + data_source_type=metadata.get("data_source_type"), + segment_id=metadata.get("segment_id"), + retriever_from=metadata.get("retriever_from"), + score=metadata.get("score"), + hit_count=metadata.get("segment_hit_count"), + word_count=metadata.get("segment_word_count"), + segment_position=metadata.get("segment_position"), + index_node_hash=metadata.get("segment_index_node_hash"), + content=context_dict.get("content"), + page=metadata.get("page"), + doc_metadata=metadata.get("doc_metadata"), + ) return source From fb12a3033d877a0e243fc88d5b820b74540cb038 Mon Sep 17 00:00:00 2001 From: Jyong <76649700+JohnJyong@users.noreply.github.com> Date: Fri, 30 May 2025 14:42:47 +0800 Subject: [PATCH 17/73] fix celery job not closed issue (#19268) --- api/tasks/document_indexing_sync_task.py | 2 +- api/tasks/document_indexing_task.py | 2 +- api/tasks/document_indexing_update_task.py | 2 +- api/tasks/duplicate_document_indexing_task.py | 2 +- api/tasks/recover_document_indexing_task.py | 2 +- api/tasks/retry_document_indexing_task.py | 2 +- api/tasks/sync_website_document_indexing_task.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/tasks/document_indexing_sync_task.py b/api/tasks/document_indexing_sync_task.py index fd1f6265b4..b4848be192 100644 --- a/api/tasks/document_indexing_sync_task.py +++ b/api/tasks/document_indexing_sync_task.py @@ -114,4 +114,4 @@ def document_indexing_sync_task(dataset_id: str, document_id: str): except DocumentIsPausedError as ex: logging.info(click.style(str(ex), fg="yellow")) except Exception: - pass + logging.exception("document_indexing_sync_task failed, document_id: {}".format(document_id)) diff --git a/api/tasks/document_indexing_task.py b/api/tasks/document_indexing_task.py index ee470d44e8..55cac6a9af 100644 --- a/api/tasks/document_indexing_task.py +++ b/api/tasks/document_indexing_task.py @@ -81,6 +81,6 @@ def document_indexing_task(dataset_id: str, document_ids: list): except DocumentIsPausedError as ex: logging.info(click.style(str(ex), fg="yellow")) except Exception: - pass + logging.exception("Document indexing task failed, dataset_id: {}".format(dataset_id)) finally: db.session.close() diff --git a/api/tasks/document_indexing_update_task.py b/api/tasks/document_indexing_update_task.py index b9ed11a8da..167b928f5d 100644 --- a/api/tasks/document_indexing_update_task.py +++ b/api/tasks/document_indexing_update_task.py @@ -73,6 +73,6 @@ def document_indexing_update_task(dataset_id: str, document_id: str): except DocumentIsPausedError as ex: logging.info(click.style(str(ex), fg="yellow")) except Exception: - pass + logging.exception("document_indexing_update_task failed, document_id: {}".format(document_id)) finally: db.session.close() diff --git a/api/tasks/duplicate_document_indexing_task.py b/api/tasks/duplicate_document_indexing_task.py index 100fc257ce..a6c93e110e 100644 --- a/api/tasks/duplicate_document_indexing_task.py +++ b/api/tasks/duplicate_document_indexing_task.py @@ -99,6 +99,6 @@ def duplicate_document_indexing_task(dataset_id: str, document_ids: list): except DocumentIsPausedError as ex: logging.info(click.style(str(ex), fg="yellow")) except Exception: - pass + logging.exception("duplicate_document_indexing_task failed, dataset_id: {}".format(dataset_id)) finally: db.session.close() diff --git a/api/tasks/recover_document_indexing_task.py b/api/tasks/recover_document_indexing_task.py index eada2ff9db..e7d49c78dc 100644 --- a/api/tasks/recover_document_indexing_task.py +++ b/api/tasks/recover_document_indexing_task.py @@ -43,6 +43,6 @@ def recover_document_indexing_task(dataset_id: str, document_id: str): except DocumentIsPausedError as ex: logging.info(click.style(str(ex), fg="yellow")) except Exception: - pass + logging.exception("recover_document_indexing_task failed, document_id: {}".format(document_id)) finally: db.session.close() diff --git a/api/tasks/retry_document_indexing_task.py b/api/tasks/retry_document_indexing_task.py index 7e50eb9f8d..a6e7092216 100644 --- a/api/tasks/retry_document_indexing_task.py +++ b/api/tasks/retry_document_indexing_task.py @@ -95,7 +95,7 @@ def retry_document_indexing_task(dataset_id: str, document_ids: list[str]): db.session.commit() logging.info(click.style(str(ex), fg="yellow")) redis_client.delete(retry_indexing_cache_key) - pass + logging.exception("retry_document_indexing_task failed, document_id: {}".format(document_id)) finally: db.session.close() end_at = time.perf_counter() diff --git a/api/tasks/sync_website_document_indexing_task.py b/api/tasks/sync_website_document_indexing_task.py index e75252edbe..dba0a39c2d 100644 --- a/api/tasks/sync_website_document_indexing_task.py +++ b/api/tasks/sync_website_document_indexing_task.py @@ -87,6 +87,6 @@ def sync_website_document_indexing_task(dataset_id: str, document_id: str): db.session.commit() logging.info(click.style(str(ex), fg="yellow")) redis_client.delete(sync_indexing_cache_key) - pass + logging.exception("sync_website_document_indexing_task failed, document_id: {}".format(document_id)) end_at = time.perf_counter() logging.info(click.style("Sync document: {} latency: {}".format(document_id, end_at - start_at), fg="green")) From 55371e5abf63ea2bc1cc136dead9cac371b9a3e8 Mon Sep 17 00:00:00 2001 From: Yasuhiro Ohno <84763339+yasu-oh@users.noreply.github.com> Date: Fri, 30 May 2025 15:43:51 +0900 Subject: [PATCH 18/73] Improve CONVERSATION_TITLE_PROMPT to correctly handle Japanese and input (#20351) --- api/core/llm_generator/prompts.py | 67 ++++++------------------------- 1 file changed, 13 insertions(+), 54 deletions(-) diff --git a/api/core/llm_generator/prompts.py b/api/core/llm_generator/prompts.py index 34ea3aec26..ddfa1e7a66 100644 --- a/api/core/llm_generator/prompts.py +++ b/api/core/llm_generator/prompts.py @@ -1,61 +1,20 @@ -# Written by YORKI MINAKO🤡, Edited by Xiaoyi -CONVERSATION_TITLE_PROMPT = """You need to decompose the user's input into "subject" and "intention" in order to accurately figure out what the user's input language actually is. -Notice: the language type user uses could be diverse, which can be English, Chinese, Italian, Español, Arabic, Japanese, French, and etc. -ENSURE your output is in the SAME language as the user's input! -Your output is restricted only to: (Input language) Intention + Subject(short as possible) -Your output MUST be a valid JSON. +# Written by YORKI MINAKO🤡, Edited by Xiaoyi, Edited by yasu-oh +CONVERSATION_TITLE_PROMPT = """You are asked to generate a concise chat title by decomposing the user’s input into two parts: “Intention” and “Subject”. -Tip: When the user's question is directed at you (the language model), you can add an emoji to make it more fun. +1. Detect Input Language +Automatically identify the language of the user’s input (e.g. English, Chinese, Italian, Español, Arabic, Japanese, French, and etc.). +2. Generate Title +- Combine Intention + Subject into a single, as-short-as-possible phrase. +- The title must be natural, friendly, and in the same language as the input. +- If the input is a direct question to the model, you may add an emoji at the end. -example 1: -User Input: hi, yesterday i had some burgers. +3. Output Format +Return **only** a valid JSON object with these exact keys and no additional text: { - "Language Type": "The user's input is pure English", - "Your Reasoning": "The language of my output must be pure English.", - "Your Output": "sharing yesterday's food" -} - -example 2: -User Input: hello -{ - "Language Type": "The user's input is pure English", - "Your Reasoning": "The language of my output must be pure English.", - "Your Output": "Greeting myself☺️" -} - - -example 3: -User Input: why mmap file: oom -{ - "Language Type": "The user's input is written in pure English", - "Your Reasoning": "The language of my output must be pure English.", - "Your Output": "Asking about the reason for mmap file: oom" -} - - -example 4: -User Input: www.convinceme.yesterday-you-ate-seafood.tv讲了什么? -{ - "Language Type": "The user's input English-Chinese mixed", - "Your Reasoning": "The English-part is an URL, the main intention is still written in Chinese, so the language of my output must be using Chinese.", - "Your Output": "询问网站www.convinceme.yesterday-you-ate-seafood.tv" -} - -example 5: -User Input: why小红的年龄is老than小明? -{ - "Language Type": "The user's input is English-Chinese mixed", - "Your Reasoning": "The English parts are filler words, the main intention is written in Chinese, besides, Chinese occupies a greater \"actual meaning\" than English, so the language of my output must be using Chinese.", - "Your Output": "询问小红和小明的年龄" -} - -example 6: -User Input: yo, 你今天咋样? -{ - "Language Type": "The user's input is English-Chinese mixed", - "Your Reasoning": "The English-part is a subjective particle, the main intention is written in Chinese, so the language of my output must be using Chinese.", - "Your Output": "查询今日我的状态☺️" + "Language Type": "", + "Your Reasoning": "", + "Your Output": "" } User Input: From 1ea4459d9f741c849324924d7148bf412da3b0cb Mon Sep 17 00:00:00 2001 From: Dongyu Li <544104925@qq.com> Date: Fri, 30 May 2025 14:45:30 +0800 Subject: [PATCH 19/73] update knowledge base api (#20426) --- .../service_api/dataset/segment.py | 22 +++ api/core/rag/retrieval/dataset_retrieval.py | 3 + api/services/hit_testing_service.py | 30 +++- .../datasets/template/template.en.mdx | 139 +++++++++++++++--- .../datasets/template/template.ja.mdx | 135 +++++++++++++++-- .../datasets/template/template.zh.mdx | 106 ++++++++++++- 6 files changed, 398 insertions(+), 37 deletions(-) diff --git a/api/controllers/service_api/dataset/segment.py b/api/controllers/service_api/dataset/segment.py index ea4be4e511..337752275a 100644 --- a/api/controllers/service_api/dataset/segment.py +++ b/api/controllers/service_api/dataset/segment.py @@ -208,6 +208,28 @@ class DatasetSegmentApi(DatasetApiResource): ) return {"data": marshal(updated_segment, segment_fields), "doc_form": document.doc_form}, 200 + def get(self, tenant_id, dataset_id, document_id, segment_id): + # check dataset + dataset_id = str(dataset_id) + tenant_id = str(tenant_id) + dataset = db.session.query(Dataset).filter(Dataset.tenant_id == tenant_id, Dataset.id == dataset_id).first() + if not dataset: + raise NotFound("Dataset not found.") + # check user's model setting + DatasetService.check_dataset_model_setting(dataset) + # check document + document_id = str(document_id) + document = DocumentService.get_document(dataset_id, document_id) + if not document: + raise NotFound("Document not found.") + # check segment + segment_id = str(segment_id) + segment = SegmentService.get_segment_by_id(segment_id=segment_id, tenant_id=current_user.current_tenant_id) + if not segment: + raise NotFound("Segment not found.") + + return {"data": marshal(segment, segment_fields), "doc_form": document.doc_form}, 200 + class ChildChunkApi(DatasetApiResource): """Resource for child chunks.""" diff --git a/api/core/rag/retrieval/dataset_retrieval.py b/api/core/rag/retrieval/dataset_retrieval.py index f668148428..6978860529 100644 --- a/api/core/rag/retrieval/dataset_retrieval.py +++ b/api/core/rag/retrieval/dataset_retrieval.py @@ -937,6 +937,9 @@ class DatasetRetrieval: return metadata_filter_document_ids, metadata_condition def _replace_metadata_filter_value(self, text: str, inputs: dict) -> str: + if not inputs: + return text + def replacer(match): key = match.group(1) return str(inputs.get(key, f"{{{{{key}}}}}")) diff --git a/api/services/hit_testing_service.py b/api/services/hit_testing_service.py index 56e06cc33e..519d5abca5 100644 --- a/api/services/hit_testing_service.py +++ b/api/services/hit_testing_service.py @@ -2,8 +2,11 @@ import logging import time from typing import Any +from core.app.app_config.entities import ModelConfig +from core.model_runtime.entities import LLMMode from core.rag.datasource.retrieval_service import RetrievalService from core.rag.models.document import Document +from core.rag.retrieval.dataset_retrieval import DatasetRetrieval from core.rag.retrieval.retrieval_methods import RetrievalMethod from extensions.ext_database import db from models.account import Account @@ -34,7 +37,29 @@ class HitTestingService: # get retrieval model , if the model is not setting , using default if not retrieval_model: retrieval_model = dataset.retrieval_model or default_retrieval_model - + document_ids_filter = None + metadata_filtering_conditions = retrieval_model.get("metadata_filtering_conditions", {}) + if metadata_filtering_conditions: + dataset_retrieval = DatasetRetrieval() + + from core.app.app_config.entities import MetadataFilteringCondition + + metadata_filtering_conditions = MetadataFilteringCondition(**metadata_filtering_conditions) + + metadata_filter_document_ids, metadata_condition = dataset_retrieval.get_metadata_filter_condition( + dataset_ids=[dataset.id], + query=query, + metadata_filtering_mode="manual", + metadata_filtering_conditions=metadata_filtering_conditions, + inputs={}, + tenant_id="", + user_id="", + metadata_model_config=ModelConfig(provider="", name="", mode=LLMMode.CHAT, completion_params={}), + ) + if metadata_filter_document_ids: + document_ids_filter = metadata_filter_document_ids.get(dataset.id, []) + if metadata_condition and not document_ids_filter: + return cls.compact_retrieve_response(query, []) all_documents = RetrievalService.retrieve( retrieval_method=retrieval_model.get("search_method", "semantic_search"), dataset_id=dataset.id, @@ -48,6 +73,7 @@ class HitTestingService: else None, reranking_mode=retrieval_model.get("reranking_mode") or "reranking_model", weights=retrieval_model.get("weights", None), + document_ids_filter=document_ids_filter, ) end = time.perf_counter() @@ -99,7 +125,7 @@ class HitTestingService: return dict(cls.compact_external_retrieve_response(dataset, query, all_documents)) @classmethod - def compact_retrieve_response(cls, query: str, documents: list[Document]): + def compact_retrieve_response(cls, query: str, documents: list[Document]) -> dict[Any, Any]: records = RetrievalService.format_retrieval_documents(documents) return { diff --git a/web/app/(commonLayout)/datasets/template/template.en.mdx b/web/app/(commonLayout)/datasets/template/template.en.mdx index 3393c636cd..1a0979b412 100644 --- a/web/app/(commonLayout)/datasets/template/template.en.mdx +++ b/web/app/(commonLayout)/datasets/template/template.en.mdx @@ -1298,6 +1298,76 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi
+ + +
+ Get details of a specific document segment in the specified knowledge base + + ### Path + + + Knowledge Base ID + + + Document ID + + + Segment ID + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ + --header 'Authorization: Bearer {api_key}' + ``` + + + ```json {{ title: 'Response' }} + { + "data": { + "id": "chunk_id", + "position": 2, + "document_id": "document_id", + "content": "Segment content text", + "sign_content": "Signature content text", + "answer": "Answer content (if in Q&A mode)", + "word_count": 470, + "tokens": 382, + "keywords": ["keyword1", "keyword2"], + "index_node_id": "index_node_id", + "index_node_hash": "index_node_hash", + "hit_count": 0, + "enabled": true, + "status": "completed", + "created_by": "creator_id", + "created_at": creation_timestamp, + "updated_at": update_timestamp, + "indexing_at": indexing_timestamp, + "completed_at": completion_timestamp, + "error": null, + "child_chunks": [] + }, + "doc_form": "text_model" + } + ``` + + + + +
+ - Retrieval model (optional, if not filled, it will be recalled according to the default method) - - search_method (text) Search method: One of the following four keywords is required - - keyword_search Keyword search - - semantic_search Semantic search - - full_text_search Full-text search - - hybrid_search Hybrid search - - reranking_enable (bool) Whether to enable reranking, required if the search mode is semantic_search or hybrid_search (optional) - - reranking_mode (object) Rerank model configuration, required if reranking is enabled - - reranking_provider_name (string) Rerank model provider - - reranking_model_name (string) Rerank model name - - weights (float) Semantic search weight setting in hybrid search mode - - top_k (integer) Number of results to return (optional) - - score_threshold_enabled (bool) Whether to enable score threshold - - score_threshold (float) Score threshold + Retrieval parameters (optional, if not filled, it will be recalled according to the default method) + - search_method (text) Search method: One of the following four keywords is required + - keyword_search Keyword search + - semantic_search Semantic search + - full_text_search Full-text search + - hybrid_search Hybrid search + - reranking_enable (bool) Whether to enable reranking, required if the search mode is semantic_search or hybrid_search (optional) + - reranking_mode (object) Rerank model configuration, required if reranking is enabled + - reranking_provider_name (string) Rerank model provider + - reranking_model_name (string) Rerank model name + - weights (float) Semantic search weight setting in hybrid search mode + - top_k (integer) Number of results to return (optional) + - score_threshold_enabled (bool) Whether to enable score threshold + - score_threshold (float) Score threshold + - metadata_filtering_conditions (object) Metadata filtering conditions + - logical_operator (string) Logical operator: and | or + - conditions (array[object]) Conditions list + - name (string) Metadata field name + - comparison_operator (string) Comparison operator, allowed values: + - String comparison: + - contains: Contains + - not contains: Does not contain + - start with: Starts with + - end with: Ends with + - is: Equals + - is not: Does not equal + - empty: Is empty + - not empty: Is not empty + - Numeric comparison: + - =: Equals + - : Does not equal + - >: Greater than + - < : Less than + - : Greater than or equal + - : Less than or equal + - Time comparison: + - before: Before + - after: After + - value (string|number|null) Comparison value Unused field @@ -1809,7 +1904,17 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi "weights": null, "top_k": 1, "score_threshold_enabled": false, - "score_threshold": null + "score_threshold": null, + "metadata_filtering_conditions": { + "logical_operator": "and", + "conditions": [ + { + "name": "document_name", + "comparison_operator": "contains", + "value": "test" + } + ] + } } }'`} > @@ -2089,9 +2194,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi label="/datasets/{dataset_id}/documents/metadata" targetCode={`curl --location --request POST '${props.apiBaseUrl}/datasets/{dataset_id}/documents/metadata' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json'\\\n--data-raw '{"operation_data": [{"document_id": "document_id", "metadata_list": [{"id": "id", "value": "value", "name": "name"}]}]}'`} > - ```bash {{ title: 'cURL' }} - ``` - + ```bash {{ title: 'cURL' }} diff --git a/web/app/(commonLayout)/datasets/template/template.ja.mdx b/web/app/(commonLayout)/datasets/template/template.ja.mdx index defd48816d..f194c8012e 100644 --- a/web/app/(commonLayout)/datasets/template/template.ja.mdx +++ b/web/app/(commonLayout)/datasets/template/template.ja.mdx @@ -1057,6 +1057,75 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi + +
+ 指定されたナレッジベース内の特定のドキュメントセグメントの詳細を表示します + + ### パス + + + ナレッジベースID + + + ドキュメントID + + + セグメントID + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ + --header 'Authorization: Bearer {api_key}' + ``` + + + ```json {{ title: 'Response' }} + { + "data": { + "id": "セグメントID", + "position": 2, + "document_id": "ドキュメントID", + "content": "セグメント内容テキスト", + "sign_content": "署名内容テキスト", + "answer": "回答内容(Q&Aモードの場合)", + "word_count": 470, + "tokens": 382, + "keywords": ["キーワード1", "キーワード2"], + "index_node_id": "インデックスノードID", + "index_node_hash": "インデックスノードハッシュ", + "hit_count": 0, + "enabled": true, + "status": "completed", + "created_by": "作成者ID", + "created_at": 作成タイムスタンプ, + "updated_at": 更新タイムスタンプ, + "indexing_at": インデックス作成タイムスタンプ, + "completed_at": 完了タイムスタンプ, + "error": null, + "child_chunks": [] + }, + "doc_form": "text_model" + } + ``` + + + + +
+ + - 検索モデル (オプション、入力されない場合はデフォルトの方法でリコールされます) - - search_method (text) 検索方法: 以下の 4 つのキーワードのいずれかが必要です - - keyword_search キーワード検索 - - semantic_search セマンティック検索 - - full_text_search 全文検索 - - hybrid_search ハイブリッド検索 - - reranking_enable (bool) 再ランキングを有効にするかどうか、検索モードが semantic_search または hybrid_search の場合に必須 (オプション) - - reranking_mode (object) 再ランキングモデル構成、再ランキングが有効な場合に必須 - - reranking_provider_name (string) 再ランキングモデルプロバイダー - - reranking_model_name (string) 再ランキングモデル名 - - weights (float) ハイブリッド検索モードでのセマンティック検索の重み設定 - - top_k (integer) 返される結果の数 (オプション) - - score_threshold_enabled (bool) スコア閾値を有効にするかどうか - - score_threshold (float) スコア閾値 + 検索パラメータ(オプション、入力されない場合はデフォルトの方法でリコールされます) + - search_method (text) 検索方法: 以下の4つのキーワードのいずれかが必要です + - keyword_search キーワード検索 + - semantic_search セマンティック検索 + - full_text_search 全文検索 + - hybrid_search ハイブリッド検索 + - reranking_enable (bool) 再ランキングを有効にするかどうか、検索モードがsemantic_searchまたはhybrid_searchの場合に必須(オプション) + - reranking_mode (object) 再ランキングモデル構成、再ランキングが有効な場合に必須 + - reranking_provider_name (string) 再ランキングモデルプロバイダー + - reranking_model_name (string) 再ランキングモデル名 + - weights (float) ハイブリッド検索モードでのセマンティック検索の重み設定 + - top_k (integer) 返される結果の数(オプション) + - score_threshold_enabled (bool) スコア閾値を有効にするかどうか + - score_threshold (float) スコア閾値 + - metadata_filtering_conditions (object) メタデータフィルタリング条件 + - logical_operator (string) 論理演算子: and | or + - conditions (array[object]) 条件リスト + - name (string) メタデータフィールド名 + - comparison_operator (string) 比較演算子、許可される値: + - 文字列比較: + - contains: 含む + - not contains: 含まない + - start with: で始まる + - end with: で終わる + - is: 等しい + - is not: 等しくない + - empty: 空 + - not empty: 空でない + - 数値比較: + - =: 等しい + - : 等しくない + - >: より大きい + - < : より小さい + - : 以上 + - : 以下 + - 時間比較: + - before: より前 + - after: より後 + - value (string|number|null) 比較値 未使用フィールド @@ -1566,7 +1659,17 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi "weights": null, "top_k": 1, "score_threshold_enabled": false, - "score_threshold": null + "score_threshold": null, + "metadata_filtering_conditions": { + "logical_operator": "and", + "conditions": [ + { + "name": "document_name", + "comparison_operator": "contains", + "value": "test" + } + ] + } } }'`} > diff --git a/web/app/(commonLayout)/datasets/template/template.zh.mdx b/web/app/(commonLayout)/datasets/template/template.zh.mdx index 04b5837651..95bc4d6aa3 100644 --- a/web/app/(commonLayout)/datasets/template/template.zh.mdx +++ b/web/app/(commonLayout)/datasets/template/template.zh.mdx @@ -1351,6 +1351,75 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi + +
+ 查看指定知识库中特定文档的分段详情 + + ### Path + + + 知识库 ID + + + 文档 ID + + + 分段 ID + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request GET '${props.apiBaseUrl}/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}' \ + --header 'Authorization: Bearer {api_key}' + ``` + + + ```json {{ title: 'Response' }} + { + "data": { + "id": "分段唯一ID", + "position": 2, + "document_id": "所属文档ID", + "content": "分段内容文本", + "sign_content": "签名内容文本", + "answer": "答案内容(如果有)", + "word_count": 470, + "tokens": 382, + "keywords": ["关键词1", "关键词2"], + "index_node_id": "索引节点ID", + "index_node_hash": "索引节点哈希值", + "hit_count": 0, + "enabled": true, + "status": "completed", + "created_by": "创建者ID", + "created_at": 创建时间戳, + "updated_at": 更新时间戳, + "indexing_at": 索引时间戳, + "completed_at": 完成时间戳, + "error": null, + "child_chunks": [] + }, + "doc_form": "text_model" + } + ``` + + + + +
+ +top_k (integer) 返回结果数量,非必填 - score_threshold_enabled (bool) 是否开启 score 阈值 - score_threshold (float) Score 阈值 + - metadata_filtering_conditions (object) 元数据过滤条件 + - logical_operator (string) 逻辑运算符: and | or + - conditions (array[object]) 条件列表 + - name (string) 元数据字段名 + - comparison_operator (string) 比较运算符,可选值: + - 字符串比较: + - contains: 包含 + - not contains: 不包含 + - start with: 以...开头 + - end with: 以...结尾 + - is: 等于 + - is not: 不等于 + - empty: 为空 + - not empty: 不为空 + - 数值比较: + - =: 等于 + - : 不等于 + - >: 大于 + - < : 小于 + - : 大于等于 + - : 小于等于 + - 时间比较: + - before: 早于 + - after: 晚于 + - value (string|number|null) 比较值 未启用字段 @@ -1851,7 +1945,17 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi "weights": null, "top_k": 1, "score_threshold_enabled": false, - "score_threshold": null + "score_threshold": null, + "metadata_filtering_conditions": { + "logical_operator": "and", + "conditions": [ + { + "name": "document_name", + "comparison_operator": "contains", + "value": "test" + } + ] + } } }'`} > From 51f64797cd779e8951ca3513c79c4802624c749a Mon Sep 17 00:00:00 2001 From: Ganondorf <364776488@qq.com> Date: Fri, 30 May 2025 14:48:00 +0800 Subject: [PATCH 20/73] Add APIs for Knowledge Base Tag Management and Dataset Binding (#20023) Co-authored-by: lizb --- .../service_api/dataset/dataset.py | 135 +++++++- api/services/tag_service.py | 15 + .../datasets/template/template.en.mdx | 310 ++++++++++++++++++ .../datasets/template/template.ja.mdx | 307 +++++++++++++++++ .../datasets/template/template.zh.mdx | 308 +++++++++++++++++ 5 files changed, 1073 insertions(+), 2 deletions(-) diff --git a/api/controllers/service_api/dataset/dataset.py b/api/controllers/service_api/dataset/dataset.py index 394f36c3ff..c100f53078 100644 --- a/api/controllers/service_api/dataset/dataset.py +++ b/api/controllers/service_api/dataset/dataset.py @@ -1,19 +1,21 @@ from flask import request -from flask_restful import marshal, reqparse +from flask_restful import marshal, marshal_with, reqparse from werkzeug.exceptions import Forbidden, NotFound import services.dataset_service from controllers.service_api import api from controllers.service_api.dataset.error import DatasetInUseError, DatasetNameDuplicateError -from controllers.service_api.wraps import DatasetApiResource +from controllers.service_api.wraps import DatasetApiResource, validate_dataset_token from core.model_runtime.entities.model_entities import ModelType from core.plugin.entities.plugin import ModelProviderID from core.provider_manager import ProviderManager from fields.dataset_fields import dataset_detail_fields +from fields.tag_fields import tag_fields from libs.login import current_user from models.dataset import Dataset, DatasetPermissionEnum from services.dataset_service import DatasetPermissionService, DatasetService from services.entities.knowledge_entities.knowledge_entities import RetrievalModel +from services.tag_service import TagService def _validate_name(name): @@ -320,5 +322,134 @@ class DatasetApi(DatasetApiResource): raise DatasetInUseError() +class DatasetTagsApi(DatasetApiResource): + @validate_dataset_token + @marshal_with(tag_fields) + def get(self, _, dataset_id): + """Get all knowledge type tags.""" + tags = TagService.get_tags("knowledge", current_user.current_tenant_id) + + return tags, 200 + + @validate_dataset_token + def post(self, _, dataset_id): + """Add a knowledge type tag.""" + if not (current_user.is_editor or current_user.is_dataset_editor): + raise Forbidden() + + parser = reqparse.RequestParser() + parser.add_argument( + "name", + nullable=False, + required=True, + help="Name must be between 1 to 50 characters.", + type=DatasetTagsApi._validate_tag_name, + ) + + args = parser.parse_args() + args["type"] = "knowledge" + tag = TagService.save_tags(args) + + response = {"id": tag.id, "name": tag.name, "type": tag.type, "binding_count": 0} + + return response, 200 + + @validate_dataset_token + def patch(self, _, dataset_id): + if not (current_user.is_editor or current_user.is_dataset_editor): + raise Forbidden() + + parser = reqparse.RequestParser() + parser.add_argument( + "name", + nullable=False, + required=True, + help="Name must be between 1 to 50 characters.", + type=DatasetTagsApi._validate_tag_name, + ) + parser.add_argument("tag_id", nullable=False, required=True, help="Id of a tag.", type=str) + args = parser.parse_args() + tag = TagService.update_tags(args, args.get("tag_id")) + + binding_count = TagService.get_tag_binding_count(args.get("tag_id")) + + response = {"id": tag.id, "name": tag.name, "type": tag.type, "binding_count": binding_count} + + return response, 200 + + @validate_dataset_token + def delete(self, _, dataset_id): + """Delete a knowledge type tag.""" + if not current_user.is_editor: + raise Forbidden() + parser = reqparse.RequestParser() + parser.add_argument("tag_id", nullable=False, required=True, help="Id of a tag.", type=str) + args = parser.parse_args() + TagService.delete_tag(args.get("tag_id")) + + return 204 + + @staticmethod + def _validate_tag_name(name): + if not name or len(name) < 1 or len(name) > 50: + raise ValueError("Name must be between 1 to 50 characters.") + return name + + +class DatasetTagBindingApi(DatasetApiResource): + @validate_dataset_token + def post(self, _, dataset_id): + # The role of the current user in the ta table must be admin, owner, editor, or dataset_operator + if not (current_user.is_editor or current_user.is_dataset_editor): + raise Forbidden() + + parser = reqparse.RequestParser() + parser.add_argument( + "tag_ids", type=list, nullable=False, required=True, location="json", help="Tag IDs is required." + ) + parser.add_argument( + "target_id", type=str, nullable=False, required=True, location="json", help="Target Dataset ID is required." + ) + + args = parser.parse_args() + args["type"] = "knowledge" + TagService.save_tag_binding(args) + + return 204 + + +class DatasetTagUnbindingApi(DatasetApiResource): + @validate_dataset_token + def post(self, _, dataset_id): + # The role of the current user in the ta table must be admin, owner, editor, or dataset_operator + if not (current_user.is_editor or current_user.is_dataset_editor): + raise Forbidden() + + parser = reqparse.RequestParser() + parser.add_argument("tag_id", type=str, nullable=False, required=True, help="Tag ID is required.") + parser.add_argument("target_id", type=str, nullable=False, required=True, help="Target ID is required.") + + args = parser.parse_args() + args["type"] = "knowledge" + TagService.delete_tag_binding(args) + + return 204 + + +class DatasetTagsBindingStatusApi(DatasetApiResource): + @validate_dataset_token + def get(self, _, *args, **kwargs): + """Get all knowledge type tags.""" + dataset_id = kwargs.get("dataset_id") + tags = TagService.get_tags_by_target_id("knowledge", current_user.current_tenant_id, str(dataset_id)) + tags_list = [{"id": tag.id, "name": tag.name} for tag in tags] + response = {"data": tags_list, "total": len(tags)} + return response, 200 + + api.add_resource(DatasetListApi, "/datasets") api.add_resource(DatasetApi, "/datasets/") +api.add_resource(DatasetTagsApi, "/datasets/tags") +api.add_resource(DatasetTagBindingApi, "/datasets/tags/binding") +api.add_resource(DatasetTagUnbindingApi, "/datasets/tags/unbinding") +api.add_resource(DatasetTagsBindingStatusApi, "/datasets//tags") diff --git a/api/services/tag_service.py b/api/services/tag_service.py index 21cb861f87..be748e8dd1 100644 --- a/api/services/tag_service.py +++ b/api/services/tag_service.py @@ -44,6 +44,17 @@ class TagService: results = [tag_binding.target_id for tag_binding in tag_bindings] return results + @staticmethod + def get_tag_by_tag_name(tag_type: str, current_tenant_id: str, tag_name: str) -> list: + tags = ( + db.session.query(Tag) + .filter(Tag.name == tag_name, Tag.tenant_id == current_tenant_id, Tag.type == tag_type) + .all() + ) + if not tags: + return [] + return tags + @staticmethod def get_tags_by_target_id(tag_type: str, current_tenant_id: str, target_id: str) -> list: tags = ( @@ -62,6 +73,8 @@ class TagService: @staticmethod def save_tags(args: dict) -> Tag: + if TagService.get_tag_by_tag_name(args["type"], current_user.current_tenant_id, args["name"]): + raise ValueError("Tag name already exists") tag = Tag( id=str(uuid.uuid4()), name=args["name"], @@ -75,6 +88,8 @@ class TagService: @staticmethod def update_tags(args: dict, tag_id: str) -> Tag: + if TagService.get_tag_by_tag_name(args["type"], current_user.current_tenant_id, args["name"]): + raise ValueError("Tag name already exists") tag = db.session.query(Tag).filter(Tag.id == tag_id).first() if not tag: raise NotFound("Tag not found") diff --git a/web/app/(commonLayout)/datasets/template/template.en.mdx b/web/app/(commonLayout)/datasets/template/template.en.mdx index 1a0979b412..4d00b7b2b5 100644 --- a/web/app/(commonLayout)/datasets/template/template.en.mdx +++ b/web/app/(commonLayout)/datasets/template/template.en.mdx @@ -2349,6 +2349,316 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi
+Okay, I will translate the Chinese text in your document while keeping all formatting and code content unchanged. + + + +
+ ### Request Body + + + (text) New tag name, required, maximum length 50 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"name": "testtag1"}' + ``` + + + ```json {{ title: 'Response' }} + { + "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", + "name": "testtag1", + "type": "knowledge", + "binding_count": 0 + } + ``` + + + + + +
+ + + +
+ ### Request Body + + + + ```bash {{ title: 'cURL' }} + curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' + ``` + + + ```json {{ title: 'Response' }} + [ + { + "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0", + "name": "testtag1", + "type": "knowledge", + "binding_count": "0" + }, + ... + ] + ``` + + + + +
+ + + +
+ ### Request Body + + + (text) Modified tag name, required, maximum length 50 + + + (text) Tag ID, required + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' + ``` + + + ```json {{ title: 'Response' }} + { + "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", + "name": "tag-renamed", + "type": "knowledge", + "binding_count": 0 + } + ``` + + + + +
+ + + + +
+ ### Request Body + + + (text) Tag ID, required + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' + ``` + + + ```json {{ title: 'Response' }} + + {"result": "success"} + + ``` + + + + +
+ + + +
+ ### Request Body + + + (list) List of Tag IDs, required + + + (text) Dataset ID, required + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' + ``` + + + ```json {{ title: 'Response' }} + {"result": "success"} + ``` + + + + +
+ + + +
+ ### Request Body + + + (text) Tag ID, required + + + (text) Dataset ID, required + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' + ``` + + + ```json {{ title: 'Response' }} + {"result": "success"} + ``` + + + + + +
+ + + +
+ ### Path + + + (text) Dataset ID + + + + + /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`} + > + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + ``` + + + ```json {{ title: 'Response' }} + { + "data": + [ + {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524", + "name": "123" + }, + ... + ], + "total": 3 + } + ``` + + + + + +
+
diff --git a/web/app/(commonLayout)/datasets/template/template.ja.mdx b/web/app/(commonLayout)/datasets/template/template.ja.mdx index f194c8012e..b9fab19948 100644 --- a/web/app/(commonLayout)/datasets/template/template.ja.mdx +++ b/web/app/(commonLayout)/datasets/template/template.ja.mdx @@ -2001,6 +2001,313 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi +
+ + +
+ ### Request Body + + + (text) 新しいタグ名、必須、最大長50文字 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"name": "testtag1"}' + ``` + + + ```json {{ title: 'Response' }} + { + "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", + "name": "testtag1", + "type": "knowledge", + "binding_count": 0 + } + ``` + + + + + +
+ + + +
+ ### Request Body + + + + ```bash {{ title: 'cURL' }} + curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' + ``` + + + ```json {{ title: 'Response' }} + [ + { + "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0", + "name": "testtag1", + "type": "knowledge", + "binding_count": "0" + }, + ... + ] + ``` + + + + +
+ + + +
+ ### Request Body + + + (text) 変更後のタグ名、必須、最大長50文字 + + + (text) タグID、必須 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' + ``` + + + ```json {{ title: 'Response' }} + { + "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", + "name": "tag-renamed", + "type": "knowledge", + "binding_count": 0 + } + ``` + + + + +
+ + + + +
+ ### Request Body + + + (text) タグID、必須 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' + ``` + + + ```json {{ title: 'Response' }} + + {"result": "success"} + + ``` + + + + +
+ + + +
+ ### Request Body + + + (list) タグIDリスト、必須 + + + (text) ナレッジベースID、必須 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' + ``` + + + ```json {{ title: 'Response' }} + {"result": "success"} + ``` + + + + +
+ + + +
+ ### Request Body + + + (text) タグID、必須 + + + (text) ナレッジベースID、必須 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' + ``` + + + ```json {{ title: 'Response' }} + {"result": "success"} + ``` + + + + + +
+ + + +
+ ### Path + + + (text) ナレッジベースID + + + + + /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`} + > + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + ``` + + + ```json {{ title: 'Response' }} + { + "data": + [ + {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524", + "name": "123" + }, + ... + ], + "total": 3 + } + ``` + + + + +
diff --git a/web/app/(commonLayout)/datasets/template/template.zh.mdx b/web/app/(commonLayout)/datasets/template/template.zh.mdx index 95bc4d6aa3..b10f22002a 100644 --- a/web/app/(commonLayout)/datasets/template/template.zh.mdx +++ b/web/app/(commonLayout)/datasets/template/template.zh.mdx @@ -2391,6 +2391,314 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi +
+ + + +
+ ### Request Body + + + (text) 新标签名称,必填,最大长度为50 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"name": "testtag1"}' + ``` + + + ```json {{ title: 'Response' }} + { + "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", + "name": "testtag1", + "type": "knowledge", + "binding_count": 0 + } + ``` + + + + + +
+ + + +
+ ### Request Body + + + + ```bash {{ title: 'cURL' }} + curl --location --request GET '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' + ``` + + + ```json {{ title: 'Response' }} + [ + { + "id": "39d6934c-ed36-463d-b4a7-377fa1503dc0", + "name": "testtag1", + "type": "knowledge", + "binding_count": "0" + }, + ... + ] + ``` + + + + +
+ + + +
+ ### Request Body + + + (text) 修改后的标签名称,必填,最大长度为50 + + + (text) 标签ID,必填 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request PATCH '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"name": "testtag2", "tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' + ``` + + + ```json {{ title: 'Response' }} + { + "id": "eddb66c2-04a1-4e3a-8cb2-75abd01e12a6", + "name": "tag-renamed", + "type": "knowledge", + "binding_count": 0 + } + ``` + + + + +
+ + + + +
+ ### Request Body + + + (text) 标签ID,必填 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request DELETE '${props.apiBaseUrl}/datasets/tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_id": "e1a0a3db-ee34-4e04-842a-81555d5316fd"}' + ``` + + + ```json {{ title: 'Response' }} + + {"result": "success"} + + ``` + + + + +
+ + + +
+ ### Request Body + + + (list) 标签ID列表,必填 + + + (text) 知识库ID,必填 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags/binding' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_ids": ["65cc29be-d072-4e26-adf4-2f727644da29","1e5348f3-d3ff-42b8-a1b7-0a86d518001a"], "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' + ``` + + + ```json {{ title: 'Response' }} + {"result": "success"} + ``` + + + + +
+ + + +
+ ### Request Body + + + (text) 标签ID,必填 + + + (text) 知识库ID,必填 + + + + + + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets/tags/unbinding' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{"tag_id": "1e5348f3-d3ff-42b8-a1b7-0a86d518001a", "target_id": "a932ea9f-fae1-4b2c-9b65-71c56e2cacd6"}' + ``` + + + ```json {{ title: 'Response' }} + {"result": "success"} + ``` + + + + + +
+ + + +
+ ### Path + + + (text) 知识库ID + + + + + /tags' \\\n--header 'Authorization: Bearer {api_key}' \\\n--header 'Content-Type: application/json' \\\n`} + > + ```bash {{ title: 'cURL' }} + curl --location --request POST '${props.apiBaseUrl}/datasets//tags' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + ``` + + + ```json {{ title: 'Response' }} + { + "data": + [ + {"id": "4a601f4f-f8a2-4166-ae7c-58c3b252a524", + "name": "123" + }, + ... + ], + "total": 3 + } + ``` + + + + +
From c8d9f8e2e4968b0179420fc8b7d25518a3439242 Mon Sep 17 00:00:00 2001 From: Kaitlyn Feng <57255247+KaitlynFeng@users.noreply.github.com> Date: Fri, 30 May 2025 14:54:30 +0800 Subject: [PATCH 21/73] fix: resolve unstable scrolling in workflow debug panel with multiple input fields #19697 (#19698) --- .../components/workflow/panel/debug-and-preview/user-input.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/components/workflow/panel/debug-and-preview/user-input.tsx b/web/app/components/workflow/panel/debug-and-preview/user-input.tsx index 096463b0fb..0670d9a52b 100644 --- a/web/app/components/workflow/panel/debug-and-preview/user-input.tsx +++ b/web/app/components/workflow/panel/debug-and-preview/user-input.tsx @@ -34,7 +34,7 @@ const UserInput = () => { return null return ( -
+
{visibleVariables.map((variable, index) => (
Date: Fri, 30 May 2025 14:56:32 +0800 Subject: [PATCH 22/73] fix: agent app tool update (#20490) --- .../config/agent/agent-tools/index.tsx | 17 +++++++++--- .../components/app/configuration/index.tsx | 5 ++-- .../install-bundle/steps/install.tsx | 8 +++++- web/context/mitt-context.tsx | 27 +++++++++++++++++++ 4 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 web/context/mitt-context.tsx diff --git a/web/app/components/app/configuration/config/agent/agent-tools/index.tsx b/web/app/components/app/configuration/config/agent/agent-tools/index.tsx index 4b773c01ba..a3149447d4 100644 --- a/web/app/components/app/configuration/config/agent/agent-tools/index.tsx +++ b/web/app/components/app/configuration/config/agent/agent-tools/index.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC } from 'react' -import React, { useMemo, useState } from 'react' +import React, { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' import copy from 'copy-to-clipboard' @@ -32,6 +32,7 @@ import cn from '@/utils/classnames' import ToolPicker from '@/app/components/workflow/block-selector/tool-picker' import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types' import { canFindTool } from '@/utils' +import { useMittContextSelector } from '@/context/mitt-context' type AgentToolWithMoreInfo = AgentTool & { icon: any; collection?: Collection } | null const AgentTools: FC = () => { @@ -39,7 +40,6 @@ const AgentTools: FC = () => { const [isShowChooseTool, setIsShowChooseTool] = useState(false) const { modelConfig, setModelConfig, collectionList } = useContext(ConfigContext) const formattingChangedDispatcher = useFormattingChangedDispatcher() - const [currentTool, setCurrentTool] = useState(null) const currentCollection = useMemo(() => { if (!currentTool) return null @@ -61,6 +61,17 @@ const AgentTools: FC = () => { collection, } }) + const useSubscribe = useMittContextSelector(s => s.useSubscribe) + const handleUpdateToolsWhenInstallToolSuccess = useCallback((installedPluginNames: string[]) => { + const newModelConfig = produce(modelConfig, (draft) => { + draft.agentConfig.tools.forEach((item: any) => { + if (item.isDeleted && installedPluginNames.includes(item.provider_id)) + item.isDeleted = false + }) + }) + setModelConfig(newModelConfig) + }, [modelConfig, setModelConfig]) + useSubscribe('plugin:install:success', handleUpdateToolsWhenInstallToolSuccess as any) const handleToolSettingChange = (value: Record) => { const newModelConfig = produce(modelConfig, (draft) => { @@ -132,7 +143,7 @@ const AgentTools: FC = () => { disabled={false} supportAddCustomTool onSelect={handleSelectTool} - selectedTools={tools} + selectedTools={tools as any} /> )} diff --git a/web/app/components/app/configuration/index.tsx b/web/app/components/app/configuration/index.tsx index 5b8f8659f8..2b97a64f5b 100644 --- a/web/app/components/app/configuration/index.tsx +++ b/web/app/components/app/configuration/index.tsx @@ -79,6 +79,7 @@ import { } from '@/utils' import PluginDependency from '@/app/components/workflow/plugin-dependency' import { supportFunctionCall } from '@/utils/tool-call' +import { MittProvider } from '@/context/mitt-context' type PublishConfig = { modelConfig: ModelConfig @@ -908,7 +909,7 @@ const Configuration: FC = () => { }} > - <> +
{/* Header */} @@ -1060,7 +1061,7 @@ const Configuration: FC = () => { /> )} - + ) diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx index ee2699b4bb..db24bdd97a 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/install.tsx @@ -9,6 +9,7 @@ import InstallMulti from './install-multi' import { useInstallOrUpdate } from '@/service/use-plugins' import useRefreshPluginList from '../../hooks/use-refresh-plugin-list' import { useCanInstallPluginFromMarketplace } from '@/app/components/plugins/plugin-page/use-permission' +import { useMittContextSelector } from '@/context/mitt-context' const i18nPrefix = 'plugin.installModal' type Props = { @@ -29,6 +30,7 @@ const Install: FC = ({ isHideButton, }) => { const { t } = useTranslation() + const emit = useMittContextSelector(s => s.emit) const [selectedPlugins, setSelectedPlugins] = React.useState([]) const [selectedIndexes, setSelectedIndexes] = React.useState([]) const selectedPluginsNum = selectedPlugins.length @@ -63,8 +65,12 @@ const Install: FC = ({ }) })) const hasInstallSuccess = res.some(r => r.success) - if (hasInstallSuccess) + if (hasInstallSuccess) { refreshPluginList(undefined, true) + emit('plugin:install:success', selectedPlugins.map((p) => { + return `${p.plugin_id}/${p.name}` + })) + } }, }) const handleInstall = () => { diff --git a/web/context/mitt-context.tsx b/web/context/mitt-context.tsx new file mode 100644 index 0000000000..2b437b0c30 --- /dev/null +++ b/web/context/mitt-context.tsx @@ -0,0 +1,27 @@ +import { createContext, useContext, useContextSelector } from 'use-context-selector' +import { useMitt } from '@/hooks/use-mitt' +import { noop } from 'lodash-es' + +type ContextValueType = ReturnType +export const MittContext = createContext({ + emit: noop, + useSubscribe: noop, +}) + +export const MittProvider = ({ children }: { children: React.ReactNode }) => { + const mitt = useMitt() + + return ( + + {children} + + ) +} + +export const useMittContext = () => { + return useContext(MittContext) +} + +export function useMittContextSelector(selector: (value: ContextValueType) => T): T { + return useContextSelector(MittContext, selector) +} From 1d9c90089c7bc7ac7ab83c982c8889ee268f962e Mon Sep 17 00:00:00 2001 From: Davide Delbianco Date: Fri, 30 May 2025 09:27:30 +0200 Subject: [PATCH 23/73] Amend color typo (#20497) Co-authored-by: Davide Delbianco --- .../icons/src/public/llm/{OpenaiTale.json => OpenaiTeal.json} | 2 +- .../icons/src/public/llm/{OpenaiTale.tsx => OpenaiTeal.tsx} | 4 ++-- web/app/components/base/icons/src/public/llm/index.ts | 2 +- .../account-setting/model-provider-page/model-icon/index.tsx | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) rename web/app/components/base/icons/src/public/llm/{OpenaiTale.json => OpenaiTeal.json} (99%) rename web/app/components/base/icons/src/public/llm/{OpenaiTale.tsx => OpenaiTeal.tsx} (86%) diff --git a/web/app/components/base/icons/src/public/llm/OpenaiTale.json b/web/app/components/base/icons/src/public/llm/OpenaiTeal.json similarity index 99% rename from web/app/components/base/icons/src/public/llm/OpenaiTale.json rename to web/app/components/base/icons/src/public/llm/OpenaiTeal.json index 45943139f1..1e85c161be 100644 --- a/web/app/components/base/icons/src/public/llm/OpenaiTale.json +++ b/web/app/components/base/icons/src/public/llm/OpenaiTeal.json @@ -33,5 +33,5 @@ } ] }, - "name": "OpenaiTale" + "name": "OpenaiTeal" } diff --git a/web/app/components/base/icons/src/public/llm/OpenaiTale.tsx b/web/app/components/base/icons/src/public/llm/OpenaiTeal.tsx similarity index 86% rename from web/app/components/base/icons/src/public/llm/OpenaiTale.tsx rename to web/app/components/base/icons/src/public/llm/OpenaiTeal.tsx index e7ae45e293..ab50b42a1e 100644 --- a/web/app/components/base/icons/src/public/llm/OpenaiTale.tsx +++ b/web/app/components/base/icons/src/public/llm/OpenaiTeal.tsx @@ -2,7 +2,7 @@ // DON NOT EDIT IT MANUALLY import * as React from 'react' -import data from './OpenaiTale.json' +import data from './OpenaiTeal.json' import IconBase from '@/app/components/base/icons/IconBase' import type { IconData } from '@/app/components/base/icons/IconBase' @@ -15,6 +15,6 @@ const Icon = ( }, ) => -Icon.displayName = 'OpenaiTale' +Icon.displayName = 'OpenaiTeal' export default Icon diff --git a/web/app/components/base/icons/src/public/llm/index.ts b/web/app/components/base/icons/src/public/llm/index.ts index c20f72d8be..fa4a1bdd10 100644 --- a/web/app/components/base/icons/src/public/llm/index.ts +++ b/web/app/components/base/icons/src/public/llm/index.ts @@ -28,9 +28,9 @@ export { default as Microsoft } from './Microsoft' export { default as OpenaiBlack } from './OpenaiBlack' export { default as OpenaiBlue } from './OpenaiBlue' export { default as OpenaiGreen } from './OpenaiGreen' +export { default as OpenaiTeal } from './OpenaiTeal' export { default as OpenaiText } from './OpenaiText' export { default as OpenaiTransparent } from './OpenaiTransparent' -export { default as OpenaiTale } from './OpenaiTale' export { default as OpenaiViolet } from './OpenaiViolet' export { default as OpenaiYellow } from './OpenaiYellow' export { default as OpenllmText } from './OpenllmText' diff --git a/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx b/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx index 6f93e2871d..df9a9cbcf7 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-icon/index.tsx @@ -5,7 +5,7 @@ import type { } from '../declarations' import { useLanguage } from '../hooks' import { Group } from '@/app/components/base/icons/src/vender/other' -import { OpenaiBlue, OpenaiTale, OpenaiViolet, OpenaiYellow } from '@/app/components/base/icons/src/public/llm' +import { OpenaiBlue, OpenaiTeal, OpenaiViolet, OpenaiYellow } from '@/app/components/base/icons/src/public/llm' import cn from '@/utils/classnames' import { renderI18nObject } from '@/i18n' @@ -25,7 +25,7 @@ const ModelIcon: FC = ({ if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.startsWith('o')) return
if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.includes('gpt-4.1')) - return
+ return
if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.includes('gpt-4o')) return
if (provider?.provider && ['openai', 'langgenius/openai/openai'].includes(provider.provider) && modelName?.startsWith('gpt-4')) From 92528360f9f5ae0d9af5a603a2824d9caffe5b9d Mon Sep 17 00:00:00 2001 From: -LAN- Date: Fri, 30 May 2025 17:15:49 +0800 Subject: [PATCH 24/73] fix: fetch tenant_id in other trace providers besides langfuse (#20495) Signed-off-by: -LAN- --- api/core/ops/base_trace_instance.py | 39 +++++++++++++++++++ api/core/ops/langfuse_trace/langfuse_trace.py | 32 ++++----------- .../ops/langsmith_trace/langsmith_trace.py | 25 ++++-------- api/core/ops/opik_trace/opik_trace.py | 25 ++++-------- api/core/ops/weave_trace/weave_trace.py | 25 ++++-------- 5 files changed, 67 insertions(+), 79 deletions(-) diff --git a/api/core/ops/base_trace_instance.py b/api/core/ops/base_trace_instance.py index f7b882fc71..8593198bc2 100644 --- a/api/core/ops/base_trace_instance.py +++ b/api/core/ops/base_trace_instance.py @@ -1,7 +1,11 @@ from abc import ABC, abstractmethod +from sqlalchemy.orm import Session + from core.ops.entities.config_entity import BaseTracingConfig from core.ops.entities.trace_entity import BaseTraceInfo +from extensions.ext_database import db +from models import Account, App, TenantAccountJoin class BaseTraceInstance(ABC): @@ -24,3 +28,38 @@ class BaseTraceInstance(ABC): Subclasses must implement specific tracing logic for activities. """ ... + + def get_service_account_with_tenant(self, app_id: str) -> Account: + """ + Get service account for an app and set up its tenant. + + Args: + app_id: The ID of the app + + Returns: + Account: The service account with tenant set up + + Raises: + ValueError: If app, creator account or tenant cannot be found + """ + with Session(db.engine, expire_on_commit=False) as session: + # Get the app to find its creator + app = session.query(App).filter(App.id == app_id).first() + if not app: + raise ValueError(f"App with id {app_id} not found") + + if not app.created_by: + raise ValueError(f"App with id {app_id} has no creator (created_by is None)") + + service_account = session.query(Account).filter(Account.id == app.created_by).first() + if not service_account: + raise ValueError(f"Creator account with id {app.created_by} not found for app {app_id}") + + current_tenant = ( + session.query(TenantAccountJoin).filter_by(account_id=service_account.id, current=True).first() + ) + if not current_tenant: + raise ValueError(f"Current tenant not found for account {service_account.id}") + service_account.set_tenant_id(current_tenant.tenant_id) + + return service_account diff --git a/api/core/ops/langfuse_trace/langfuse_trace.py b/api/core/ops/langfuse_trace/langfuse_trace.py index fa1c6b4557..0ea74e9ef0 100644 --- a/api/core/ops/langfuse_trace/langfuse_trace.py +++ b/api/core/ops/langfuse_trace/langfuse_trace.py @@ -4,7 +4,7 @@ from datetime import datetime, timedelta from typing import Optional from langfuse import Langfuse # type: ignore -from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy.orm import sessionmaker from core.ops.base_trace_instance import BaseTraceInstance from core.ops.entities.config_entity import LangfuseConfig @@ -31,8 +31,7 @@ from core.ops.utils import filter_none_values from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.workflow.nodes.enums import NodeType from extensions.ext_database import db -from models import Account, App, EndUser, WorkflowNodeExecutionTriggeredFrom -from models.account import TenantAccountJoin +from models import EndUser, WorkflowNodeExecutionTriggeredFrom logger = logging.getLogger(__name__) @@ -115,28 +114,11 @@ class LangFuseDataTrace(BaseTraceInstance): # through workflow_run_id get all_nodes_execution using repository session_factory = sessionmaker(bind=db.engine) # Find the app's creator account - with Session(db.engine, expire_on_commit=False) as session: - # Get the app to find its creator - app_id = trace_info.metadata.get("app_id") - if not app_id: - raise ValueError("No app_id found in trace_info metadata") - - app = session.query(App).filter(App.id == app_id).first() - if not app: - raise ValueError(f"App with id {app_id} not found") - - if not app.created_by: - raise ValueError(f"App with id {app_id} has no creator (created_by is None)") - - service_account = session.query(Account).filter(Account.id == app.created_by).first() - if not service_account: - raise ValueError(f"Creator account with id {app.created_by} not found for app {app_id}") - current_tenant = ( - session.query(TenantAccountJoin).filter_by(account_id=service_account.id, current=True).first() - ) - if not current_tenant: - raise ValueError(f"Current tenant not found for account {service_account.id}") - service_account.set_tenant_id(current_tenant.tenant_id) + app_id = trace_info.metadata.get("app_id") + if not app_id: + raise ValueError("No app_id found in trace_info metadata") + + service_account = self.get_service_account_with_tenant(app_id) workflow_node_execution_repository = SQLAlchemyWorkflowNodeExecutionRepository( session_factory=session_factory, diff --git a/api/core/ops/langsmith_trace/langsmith_trace.py b/api/core/ops/langsmith_trace/langsmith_trace.py index e4183ea1e2..8a392940db 100644 --- a/api/core/ops/langsmith_trace/langsmith_trace.py +++ b/api/core/ops/langsmith_trace/langsmith_trace.py @@ -6,7 +6,7 @@ from typing import Optional, cast from langsmith import Client from langsmith.schemas import RunBase -from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy.orm import sessionmaker from core.ops.base_trace_instance import BaseTraceInstance from core.ops.entities.config_entity import LangSmithConfig @@ -31,7 +31,7 @@ from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db -from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom +from models import EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom logger = logging.getLogger(__name__) @@ -139,22 +139,11 @@ class LangSmithDataTrace(BaseTraceInstance): # through workflow_run_id get all_nodes_execution using repository session_factory = sessionmaker(bind=db.engine) # Find the app's creator account - with Session(db.engine, expire_on_commit=False) as session: - # Get the app to find its creator - app_id = trace_info.metadata.get("app_id") - if not app_id: - raise ValueError("No app_id found in trace_info metadata") - - app = session.query(App).filter(App.id == app_id).first() - if not app: - raise ValueError(f"App with id {app_id} not found") - - if not app.created_by: - raise ValueError(f"App with id {app_id} has no creator (created_by is None)") - - service_account = session.query(Account).filter(Account.id == app.created_by).first() - if not service_account: - raise ValueError(f"Creator account with id {app.created_by} not found for app {app_id}") + app_id = trace_info.metadata.get("app_id") + if not app_id: + raise ValueError("No app_id found in trace_info metadata") + + service_account = self.get_service_account_with_tenant(app_id) workflow_node_execution_repository = SQLAlchemyWorkflowNodeExecutionRepository( session_factory=session_factory, diff --git a/api/core/ops/opik_trace/opik_trace.py b/api/core/ops/opik_trace/opik_trace.py index f7a4464267..f4d2760ba5 100644 --- a/api/core/ops/opik_trace/opik_trace.py +++ b/api/core/ops/opik_trace/opik_trace.py @@ -6,7 +6,7 @@ from typing import Optional, cast from opik import Opik, Trace from opik.id_helpers import uuid4_to_uuid7 -from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy.orm import sessionmaker from core.ops.base_trace_instance import BaseTraceInstance from core.ops.entities.config_entity import OpikConfig @@ -25,7 +25,7 @@ from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db -from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom +from models import EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom logger = logging.getLogger(__name__) @@ -154,22 +154,11 @@ class OpikDataTrace(BaseTraceInstance): # through workflow_run_id get all_nodes_execution using repository session_factory = sessionmaker(bind=db.engine) # Find the app's creator account - with Session(db.engine, expire_on_commit=False) as session: - # Get the app to find its creator - app_id = trace_info.metadata.get("app_id") - if not app_id: - raise ValueError("No app_id found in trace_info metadata") - - app = session.query(App).filter(App.id == app_id).first() - if not app: - raise ValueError(f"App with id {app_id} not found") - - if not app.created_by: - raise ValueError(f"App with id {app_id} has no creator (created_by is None)") - - service_account = session.query(Account).filter(Account.id == app.created_by).first() - if not service_account: - raise ValueError(f"Creator account with id {app.created_by} not found for app {app_id}") + app_id = trace_info.metadata.get("app_id") + if not app_id: + raise ValueError("No app_id found in trace_info metadata") + + service_account = self.get_service_account_with_tenant(app_id) workflow_node_execution_repository = SQLAlchemyWorkflowNodeExecutionRepository( session_factory=session_factory, diff --git a/api/core/ops/weave_trace/weave_trace.py b/api/core/ops/weave_trace/weave_trace.py index b12380be47..cfc8a505bb 100644 --- a/api/core/ops/weave_trace/weave_trace.py +++ b/api/core/ops/weave_trace/weave_trace.py @@ -6,7 +6,7 @@ from typing import Any, Optional, cast import wandb import weave -from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy.orm import sessionmaker from core.ops.base_trace_instance import BaseTraceInstance from core.ops.entities.config_entity import WeaveConfig @@ -26,7 +26,7 @@ from core.repositories import SQLAlchemyWorkflowNodeExecutionRepository from core.workflow.entities.workflow_node_execution import WorkflowNodeExecutionMetadataKey from core.workflow.nodes.enums import NodeType from extensions.ext_database import db -from models import Account, App, EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom +from models import EndUser, MessageFile, WorkflowNodeExecutionTriggeredFrom logger = logging.getLogger(__name__) @@ -133,22 +133,11 @@ class WeaveDataTrace(BaseTraceInstance): # through workflow_run_id get all_nodes_execution using repository session_factory = sessionmaker(bind=db.engine) # Find the app's creator account - with Session(db.engine, expire_on_commit=False) as session: - # Get the app to find its creator - app_id = trace_info.metadata.get("app_id") - if not app_id: - raise ValueError("No app_id found in trace_info metadata") - - app = session.query(App).filter(App.id == app_id).first() - if not app: - raise ValueError(f"App with id {app_id} not found") - - if not app.created_by: - raise ValueError(f"App with id {app_id} has no creator (created_by is None)") - - service_account = session.query(Account).filter(Account.id == app.created_by).first() - if not service_account: - raise ValueError(f"Creator account with id {app.created_by} not found for app {app_id}") + app_id = trace_info.metadata.get("app_id") + if not app_id: + raise ValueError("No app_id found in trace_info metadata") + + service_account = self.get_service_account_with_tenant(app_id) workflow_node_execution_repository = SQLAlchemyWorkflowNodeExecutionRepository( session_factory=session_factory, From e01d975b80110c1465fb72ba7d315947890c8683 Mon Sep 17 00:00:00 2001 From: Joel Date: Fri, 30 May 2025 18:13:00 +0800 Subject: [PATCH 25/73] fix: the plugin order is not the same as passed to api in DSL (#20515) --- .../install-plugin/install-bundle/steps/install-multi.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx b/web/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx index 40be3e65e6..5f60483d3c 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/steps/install-multi.tsx @@ -83,7 +83,12 @@ const InstallByDSLList: FC = ({ useEffect(() => { if (!isFetchingMarketplaceDataById && infoGetById?.data.plugins) { - const payloads = infoGetById?.data.plugins + const sortedList = allPlugins.filter(d => d.type === 'marketplace').map((d) => { + const p = d as GitHubItemAndMarketPlaceDependency + const id = p.value.marketplace_plugin_unique_identifier?.split(':')[0] + return infoGetById.data.plugins.find(item => item.plugin_id === id)! + }) + const payloads = sortedList const failedIndex: number[] = [] const nextPlugins = produce(pluginsRef.current, (draft) => { marketPlaceInDSLIndex.forEach((index, i) => { From c26e1929d6607b35d340b9597de600d9cb7df1d6 Mon Sep 17 00:00:00 2001 From: kurokobo Date: Sun, 1 Jun 2025 00:27:47 +0900 Subject: [PATCH 26/73] fix(housekeeping): exclude files that are used as app icons or avatar images from being removed (#20532) --- api/commands.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/commands.py b/api/commands.py index 66278a53a3..6262bfde6b 100644 --- a/api/commands.py +++ b/api/commands.py @@ -846,6 +846,9 @@ def clear_orphaned_file_records(force: bool): {"type": "text", "table": "workflow_node_executions", "column": "outputs"}, {"type": "text", "table": "conversations", "column": "introduction"}, {"type": "text", "table": "conversations", "column": "system_instruction"}, + {"type": "text", "table": "accounts", "column": "avatar"}, + {"type": "text", "table": "apps", "column": "icon"}, + {"type": "text", "table": "sites", "column": "icon"}, {"type": "json", "table": "messages", "column": "inputs"}, {"type": "json", "table": "messages", "column": "message"}, ] From b33f8b47ca0e6c0abc1aa34ddfca3d7042f8c9b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=9B=E9=9C=B2=E5=85=88=E7=94=9F?= Date: Sun, 1 Jun 2025 10:17:40 +0800 Subject: [PATCH 27/73] nacos config init , and force add ts parms. (#20526) Signed-off-by: zhanluxianshen --- api/configs/remote_settings_sources/nacos/http_request.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/api/configs/remote_settings_sources/nacos/http_request.py b/api/configs/remote_settings_sources/nacos/http_request.py index 2785bd955b..9b3359c6ad 100644 --- a/api/configs/remote_settings_sources/nacos/http_request.py +++ b/api/configs/remote_settings_sources/nacos/http_request.py @@ -60,8 +60,7 @@ class NacosHttpClient: sign_str = tenant + "+" if group: sign_str = sign_str + group + "+" - if sign_str: - sign_str += ts + sign_str += ts # Directly concatenate ts without conditional checks, because the nacos auth header forced it. return sign_str def get_access_token(self, force_refresh=False): From 23c9f1b4446785f2693a66b03909dc606257ba95 Mon Sep 17 00:00:00 2001 From: kenwoodjw Date: Mon, 2 Jun 2025 18:02:50 +0800 Subject: [PATCH 28/73] fix ts5097 (#20543) Signed-off-by: kenwoodjw --- ...-selector.tsx.tsx => condition-common-variable-selector.tsx} | 0 .../components/metadata/condition-list/condition-number.tsx | 2 +- .../components/metadata/condition-list/condition-string.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/{condition-common-variable-selector.tsx.tsx => condition-common-variable-selector.tsx} (100%) diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx similarity index 100% rename from web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx.tsx rename to web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-number.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-number.tsx index 32fd64dec4..7016e8bd2a 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-number.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-number.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next' import ConditionValueMethod from './condition-value-method' import type { ConditionValueMethodProps } from './condition-value-method' import ConditionVariableSelector from './condition-variable-selector' -import ConditionCommonVariableSelector from './condition-common-variable-selector.tsx' +import ConditionCommonVariableSelector from './condition-common-variable-selector' import type { Node, NodeOutPutVar, diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-string.tsx b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-string.tsx index f376ee55ff..cf85f1259b 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-string.tsx +++ b/web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-string.tsx @@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next' import ConditionValueMethod from './condition-value-method' import type { ConditionValueMethodProps } from './condition-value-method' import ConditionVariableSelector from './condition-variable-selector' -import ConditionCommonVariableSelector from './condition-common-variable-selector.tsx' +import ConditionCommonVariableSelector from './condition-common-variable-selector' import type { Node, NodeOutPutVar, From b4b59148dc6602b7e48ee0be7177716688297eb1 Mon Sep 17 00:00:00 2001 From: Cheney Zhang Date: Mon, 2 Jun 2025 18:04:13 +0800 Subject: [PATCH 29/73] check zilliz cloud of full-text search (#20519) --- api/core/rag/datasource/vdb/milvus/milvus_vector.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/core/rag/datasource/vdb/milvus/milvus_vector.py b/api/core/rag/datasource/vdb/milvus/milvus_vector.py index 7b3f826082..63de6a0603 100644 --- a/api/core/rag/datasource/vdb/milvus/milvus_vector.py +++ b/api/core/rag/datasource/vdb/milvus/milvus_vector.py @@ -97,6 +97,10 @@ class MilvusVector(BaseVector): try: milvus_version = self._client.get_server_version() + # Check if it's Zilliz Cloud - it supports full-text search with Milvus 2.5 compatibility + if "Zilliz Cloud" in milvus_version: + return True + # For standard Milvus installations, check version number return version.parse(milvus_version).base_version >= version.parse("2.5.0").base_version except Exception as e: logger.warning(f"Failed to check Milvus version: {str(e)}. Disabling hybrid search.") From 8025ad06613d844ef7eb23909df3b73aced4ba43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E5=A6=82=E5=BD=92=E5=8E=BB?= Date: Mon, 2 Jun 2025 18:08:53 +0800 Subject: [PATCH 30/73] Fixes #20534: Allow $ref in parameter for custom tools (#20535) Co-authored-by: Peter Xin --- api/core/tools/utils/parser.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/core/tools/utils/parser.py b/api/core/tools/utils/parser.py index f72291783a..3f844e8234 100644 --- a/api/core/tools/utils/parser.py +++ b/api/core/tools/utils/parser.py @@ -55,6 +55,13 @@ class ApiBasedToolSchemaParser: # convert parameters parameters = [] if "parameters" in interface["operation"]: + for i, parameter in enumerate(interface["operation"]["parameters"]): + if "$ref" in parameter: + root = openapi + reference = parameter["$ref"].split("/")[1:] + for ref in reference: + root = root[ref] + interface["operation"]["parameters"][i] = root for parameter in interface["operation"]["parameters"]: tool_parameter = ToolParameter( name=parameter["name"], From c29cb503beb3d1b440a7faef680ddadff4be5ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E5=A6=82=E5=BD=92=E5=8E=BB?= Date: Mon, 2 Jun 2025 18:09:01 +0800 Subject: [PATCH 31/73] Fix #20536: Force header in custom tool be string (#20537) Co-authored-by: Peter Xin --- api/core/tools/custom_tool/tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/core/tools/custom_tool/tool.py b/api/core/tools/custom_tool/tool.py index 2f2f1ebbdd..2f5cc6d4c0 100644 --- a/api/core/tools/custom_tool/tool.py +++ b/api/core/tools/custom_tool/tool.py @@ -168,7 +168,7 @@ class ApiTool(Tool): cookies[parameter["name"]] = value elif parameter["in"] == "header": - headers[parameter["name"]] = value + headers[parameter["name"]] = str(value) # check if there is a request body and handle it if "requestBody" in self.api_bundle.openapi and self.api_bundle.openapi["requestBody"] is not None: From a145c2a8fee93c181b1d0f189031d3600435d2dc Mon Sep 17 00:00:00 2001 From: Contrail <30793677+StellaContrail@users.noreply.github.com> Date: Tue, 3 Jun 2025 13:47:39 +0900 Subject: [PATCH 32/73] fix: ensure proper conversation role alternation for vLLM (#18837) --- .../nodes/question_classifier/question_classifier_node.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/core/workflow/nodes/question_classifier/question_classifier_node.py b/api/core/workflow/nodes/question_classifier/question_classifier_node.py index e846b76280..28d8b3b867 100644 --- a/api/core/workflow/nodes/question_classifier/question_classifier_node.py +++ b/api/core/workflow/nodes/question_classifier/question_classifier_node.py @@ -79,9 +79,13 @@ class QuestionClassifierNode(LLMNode): memory=memory, max_token_limit=rest_token, ) + # Some models (e.g. Gemma, Mistral) force roles alternation (user/assistant/user/assistant...). + # If both self._get_prompt_template and self._fetch_prompt_messages append a user prompt, + # two consecutive user prompts will be generated, causing model's error. + # To avoid this, set sys_query to an empty string so that only one user prompt is appended at the end. prompt_messages, stop = self._fetch_prompt_messages( prompt_template=prompt_template, - sys_query=query, + sys_query="", memory=memory, model_config=model_config, sys_files=files, From 3f7aa38d77c8dac6779eec4075f4a386ab60bf64 Mon Sep 17 00:00:00 2001 From: zhaobingshuang <1475195565@qq.com> Date: Tue, 3 Jun 2025 13:24:26 +0800 Subject: [PATCH 33/73] fix: #20560 When elasticsearch is used as the vector database, the Retrieval Test fails to filter the data after setting the Score Threshold, and the score of the recalled results is empty (#20561) --- .../rag/datasource/vdb/elasticsearch/elasticsearch_vector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/core/rag/datasource/vdb/elasticsearch/elasticsearch_vector.py b/api/core/rag/datasource/vdb/elasticsearch/elasticsearch_vector.py index 033d05a077..44cc5d3e98 100644 --- a/api/core/rag/datasource/vdb/elasticsearch/elasticsearch_vector.py +++ b/api/core/rag/datasource/vdb/elasticsearch/elasticsearch_vector.py @@ -142,7 +142,7 @@ class ElasticSearchVector(BaseVector): if score > score_threshold: if doc.metadata is not None: doc.metadata["score"] = score - docs.append(doc) + docs.append(doc) return docs From d6b30efe2c3a0ac258e9be982861c2102a7764d2 Mon Sep 17 00:00:00 2001 From: KVOJJJin Date: Tue, 3 Jun 2025 13:53:24 +0800 Subject: [PATCH 34/73] Fix/dark theme style issues (#20566) --- web/app/components/base/radio/component/radio/index.tsx | 5 +++-- .../components/editor/code-editor/editor-support-vars.tsx | 2 +- .../nodes/_base/components/variable/var-type-picker.tsx | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/web/app/components/base/radio/component/radio/index.tsx b/web/app/components/base/radio/component/radio/index.tsx index eddc53dd7f..7788226484 100644 --- a/web/app/components/base/radio/component/radio/index.tsx +++ b/web/app/components/base/radio/component/radio/index.tsx @@ -37,14 +37,15 @@ export default function Radio({ const isChecked = groupContext ? groupContext.value === value : checked const divClassName = ` flex items-center py-1 relative - px-7 cursor-pointer hover:bg-gray-200 rounded + px-7 cursor-pointer text-text-secondary rounded + bg-components-option-card-option-bg hover:bg-components-option-card-option-bg-hover hover:shadow-xs ` return (
handleChange(value)} diff --git a/web/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars.tsx b/web/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars.tsx index 7798ed3cb2..abc7d8dbc4 100644 --- a/web/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars.tsx +++ b/web/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars.tsx @@ -148,7 +148,7 @@ const CodeEditor: FC = ({ {isShowVarPicker && (
= ({ offset={4} > setOpen(!open)} className='w-[120px] cursor-pointer'> -
+
{value}
From 744159a079d2448515cecf276a06f5017d9e4322 Mon Sep 17 00:00:00 2001 From: Joel Date: Tue, 3 Jun 2025 14:54:42 +0800 Subject: [PATCH 35/73] fix: agent thought replaced by response text (#20571) --- web/app/components/base/chat/chat/hooks.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/app/components/base/chat/chat/hooks.ts b/web/app/components/base/chat/chat/hooks.ts index fde4674539..28f297b90e 100644 --- a/web/app/components/base/chat/chat/hooks.ts +++ b/web/app/components/base/chat/chat/hooks.ts @@ -366,8 +366,9 @@ export const useChat = ( if (!newResponseItem) return + const isUseAgentThought = newResponseItem.agent_thoughts?.length > 0 updateChatTreeNode(responseItem.id, { - content: newResponseItem.answer, + content: isUseAgentThought ? '' : newResponseItem.answer, log: [ ...newResponseItem.message, ...(newResponseItem.message[newResponseItem.message.length - 1].role !== 'assistant' From db83bfc53a77a93cf75de750a0f0941928364f78 Mon Sep 17 00:00:00 2001 From: GuanMu Date: Tue, 3 Jun 2025 15:21:53 +0800 Subject: [PATCH 36/73] chore: update pnpm version to 10.11.1 (#20573) --- .devcontainer/post_create_command.sh | 2 +- web/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/post_create_command.sh b/.devcontainer/post_create_command.sh index 62f7ee3b4d..93ecac48f2 100755 --- a/.devcontainer/post_create_command.sh +++ b/.devcontainer/post_create_command.sh @@ -1,6 +1,6 @@ #!/bin/bash -npm add -g pnpm@10.8.0 +npm add -g pnpm@10.11.1 cd web && pnpm install pipx install uv diff --git a/web/Dockerfile b/web/Dockerfile index dfc5ba8b46..93eef59815 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -6,7 +6,7 @@ LABEL maintainer="takatost@gmail.com" # RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories RUN apk add --no-cache tzdata -RUN npm install -g pnpm@10.8.0 +RUN npm install -g pnpm@10.11.1 ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" From 72fdafc180adafb81165fe6409772de27283c3c2 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 3 Jun 2025 16:16:06 +0800 Subject: [PATCH 37/73] refactor: Replaces direct DB session usage with context managers (#20569) Signed-off-by: -LAN- --- .../workflow/graph_engine/graph_engine.py | 6 --- api/core/workflow/nodes/agent/agent_node.py | 16 +++--- .../knowledge_retrieval_node.py | 18 ++++--- api/core/workflow/nodes/llm/node.py | 50 +++++++++---------- .../parameter_extractor_node.py | 3 -- 5 files changed, 43 insertions(+), 50 deletions(-) diff --git a/api/core/workflow/graph_engine/graph_engine.py b/api/core/workflow/graph_engine/graph_engine.py index 3eb99fde81..363b2ee920 100644 --- a/api/core/workflow/graph_engine/graph_engine.py +++ b/api/core/workflow/graph_engine/graph_engine.py @@ -53,7 +53,6 @@ from core.workflow.nodes.end.end_stream_processor import EndStreamProcessor from core.workflow.nodes.enums import ErrorStrategy, FailBranchSourceHandle from core.workflow.nodes.event import RunCompletedEvent, RunRetrieverResourceEvent, RunStreamChunkEvent from core.workflow.nodes.node_mapping import NODE_TYPE_CLASSES_MAPPING -from extensions.ext_database import db from models.enums import UserFrom from models.workflow import WorkflowType @@ -607,8 +606,6 @@ class GraphEngine: error=str(e), ) ) - finally: - db.session.remove() def _run_node( self, @@ -646,7 +643,6 @@ class GraphEngine: agent_strategy=agent_strategy, ) - db.session.close() max_retries = node_instance.node_data.retry_config.max_retries retry_interval = node_instance.node_data.retry_config.retry_interval_seconds retries = 0 @@ -863,8 +859,6 @@ class GraphEngine: except Exception as e: logger.exception(f"Node {node_instance.node_data.title} run failed") raise e - finally: - db.session.close() def _append_variables_recursively(self, node_id: str, variable_key_list: list[str], variable_value: VariableValue): """ diff --git a/api/core/workflow/nodes/agent/agent_node.py b/api/core/workflow/nodes/agent/agent_node.py index 30b17cbd84..faa8f90bea 100644 --- a/api/core/workflow/nodes/agent/agent_node.py +++ b/api/core/workflow/nodes/agent/agent_node.py @@ -2,6 +2,9 @@ import json from collections.abc import Generator, Mapping, Sequence from typing import Any, Optional, cast +from sqlalchemy import select +from sqlalchemy.orm import Session + from core.agent.entities import AgentToolEntity from core.agent.plugin_entities import AgentStrategyParameter from core.memory.token_buffer_memory import TokenBufferMemory @@ -320,15 +323,12 @@ class AgentNode(ToolNode): return None conversation_id = conversation_id_variable.value - # get conversation - conversation = ( - db.session.query(Conversation) - .filter(Conversation.app_id == self.app_id, Conversation.id == conversation_id) - .first() - ) + with Session(db.engine, expire_on_commit=False) as session: + stmt = select(Conversation).where(Conversation.app_id == self.app_id, Conversation.id == conversation_id) + conversation = session.scalar(stmt) - if not conversation: - return None + if not conversation: + return None memory = TokenBufferMemory(conversation=conversation, model_instance=model_instance) diff --git a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py b/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py index 2ddb4f8a0b..53124f962a 100644 --- a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py +++ b/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py @@ -8,6 +8,7 @@ from typing import Any, Optional, cast from sqlalchemy import Float, and_, func, or_, text from sqlalchemy import cast as sqlalchemy_cast +from sqlalchemy.orm import Session from core.app.app_config.entities import DatasetRetrieveConfigEntity from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity @@ -95,14 +96,15 @@ class KnowledgeRetrievalNode(LLMNode): redis_client.zremrangebyscore(key, 0, current_time - 60000) request_count = redis_client.zcard(key) if request_count > knowledge_rate_limit.limit: - # add ratelimit record - rate_limit_log = RateLimitLog( - tenant_id=self.tenant_id, - subscription_plan=knowledge_rate_limit.subscription_plan, - operation="knowledge", - ) - db.session.add(rate_limit_log) - db.session.commit() + with Session(db.engine) as session: + # add ratelimit record + rate_limit_log = RateLimitLog( + tenant_id=self.tenant_id, + subscription_plan=knowledge_rate_limit.subscription_plan, + operation="knowledge", + ) + session.add(rate_limit_log) + session.commit() return NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs=variables, diff --git a/api/core/workflow/nodes/llm/node.py b/api/core/workflow/nodes/llm/node.py index 0fd7c31ffb..df8f614db3 100644 --- a/api/core/workflow/nodes/llm/node.py +++ b/api/core/workflow/nodes/llm/node.py @@ -7,6 +7,8 @@ from datetime import UTC, datetime from typing import TYPE_CHECKING, Any, Optional, cast import json_repair +from sqlalchemy import select, update +from sqlalchemy.orm import Session from configs import dify_config from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity @@ -303,8 +305,6 @@ class LLMNode(BaseNode[LLMNodeData]): prompt_messages: Sequence[PromptMessage], stop: Optional[Sequence[str]] = None, ) -> Generator[NodeEvent, None, None]: - db.session.close() - invoke_result = model_instance.invoke_llm( prompt_messages=list(prompt_messages), model_parameters=node_data_model.completion_params, @@ -603,15 +603,11 @@ class LLMNode(BaseNode[LLMNodeData]): return None conversation_id = conversation_id_variable.value - # get conversation - conversation = ( - db.session.query(Conversation) - .filter(Conversation.app_id == self.app_id, Conversation.id == conversation_id) - .first() - ) - - if not conversation: - return None + with Session(db.engine, expire_on_commit=False) as session: + stmt = select(Conversation).where(Conversation.app_id == self.app_id, Conversation.id == conversation_id) + conversation = session.scalar(stmt) + if not conversation: + return None memory = TokenBufferMemory(conversation=conversation, model_instance=model_instance) @@ -847,20 +843,24 @@ class LLMNode(BaseNode[LLMNodeData]): used_quota = 1 if used_quota is not None and system_configuration.current_quota_type is not None: - db.session.query(Provider).filter( - Provider.tenant_id == tenant_id, - # TODO: Use provider name with prefix after the data migration. - Provider.provider_name == ModelProviderID(model_instance.provider).provider_name, - Provider.provider_type == ProviderType.SYSTEM.value, - Provider.quota_type == system_configuration.current_quota_type.value, - Provider.quota_limit > Provider.quota_used, - ).update( - { - "quota_used": Provider.quota_used + used_quota, - "last_used": datetime.now(tz=UTC).replace(tzinfo=None), - } - ) - db.session.commit() + with Session(db.engine) as session: + stmt = ( + update(Provider) + .where( + Provider.tenant_id == tenant_id, + # TODO: Use provider name with prefix after the data migration. + Provider.provider_name == ModelProviderID(model_instance.provider).provider_name, + Provider.provider_type == ProviderType.SYSTEM.value, + Provider.quota_type == system_configuration.current_quota_type.value, + Provider.quota_limit > Provider.quota_used, + ) + .values( + quota_used=Provider.quota_used + used_quota, + last_used=datetime.now(tz=UTC).replace(tzinfo=None), + ) + ) + session.execute(stmt) + session.commit() @classmethod def _extract_variable_selector_to_variable_mapping( diff --git a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py index ea4070e224..4f31258b15 100644 --- a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py +++ b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py @@ -31,7 +31,6 @@ from core.workflow.entities.workflow_node_execution import WorkflowNodeExecution from core.workflow.nodes.enums import NodeType from core.workflow.nodes.llm import LLMNode, ModelConfig from core.workflow.utils import variable_template_parser -from extensions.ext_database import db from .entities import ParameterExtractorNodeData from .exc import ( @@ -259,8 +258,6 @@ class ParameterExtractorNode(LLMNode): tools: list[PromptMessageTool], stop: list[str], ) -> tuple[str, LLMUsage, Optional[AssistantPromptMessage.ToolCall]]: - db.session.close() - invoke_result = model_instance.invoke_llm( prompt_messages=prompt_messages, model_parameters=node_data_model.completion_params, From 957f5b212eeae6c26643c93b3396645811515fc7 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 3 Jun 2025 16:35:34 +0800 Subject: [PATCH 38/73] fix: Upgrade Flask-Cors (#20577) Signed-off-by: -LAN- --- api/pyproject.toml | 16 +- api/uv.lock | 1171 ++++++++++++++++++++++---------------------- 2 files changed, 591 insertions(+), 596 deletions(-) diff --git a/api/pyproject.toml b/api/pyproject.toml index 50a765c0e1..f497274da1 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -14,7 +14,7 @@ dependencies = [ "chardet~=5.1.0", "flask~=3.1.0", "flask-compress~=1.17", - "flask-cors~=5.0.0", + "flask-cors~=6.0.0", "flask-login~=0.6.3", "flask-migrate~=4.0.7", "flask-restful~=0.3.10", @@ -36,7 +36,6 @@ dependencies = [ "mailchimp-transactional~=1.0.50", "markdown~=3.5.1", "numpy~=1.26.4", - "oci~=2.135.1", "openai~=1.61.0", "openpyxl~=3.1.5", "opik~=1.7.25", @@ -143,13 +142,16 @@ dev = [ "types-requests~=2.32.0", "types-requests-oauthlib~=2.0.0", "types-shapely~=2.0.0", - "types-simplejson~=3.20.0", - "types-six~=1.17.0", - "types-tensorflow~=2.18.0", - "types-tqdm~=4.67.0", - "types-ujson~=5.10.0", + "types-simplejson>=3.20.0", + "types-six>=1.17.0", + "types-tensorflow>=2.18.0", + "types-tqdm>=4.67.0", + "types-ujson>=5.10.0", "boto3-stubs>=1.38.20", "types-jmespath>=1.0.2.20240106", + "types_pyOpenSSL>=24.1.0", + "types_cffi>=1.17.0", + "types_setuptools>=80.9.0", ] ############################################################ diff --git a/api/uv.lock b/api/uv.lock index a1e1d6146a..1f1ba66de7 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -36,7 +36,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.11.18" +version = "3.12.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -47,40 +47,42 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/e7/fa1a8c00e2c54b05dc8cb5d1439f627f7c267874e3f7bb047146116020f9/aiohttp-3.11.18.tar.gz", hash = "sha256:ae856e1138612b7e412db63b7708735cff4d38d0399f6a5435d3dac2669f558a", size = 7678653 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/10/fd9ee4f9e042818c3c2390054c08ccd34556a3cb209d83285616434cf93e/aiohttp-3.11.18-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:427fdc56ccb6901ff8088544bde47084845ea81591deb16f957897f0f0ba1be9", size = 712088 }, - { url = "https://files.pythonhosted.org/packages/22/eb/6a77f055ca56f7aae2cd2a5607a3c9e7b9554f1497a069dcfcb52bfc9540/aiohttp-3.11.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c828b6d23b984255b85b9b04a5b963a74278b7356a7de84fda5e3b76866597b", size = 471450 }, - { url = "https://files.pythonhosted.org/packages/78/dc/5f3c0d27c91abf0bb5d103e9c9b0ff059f60cf6031a5f06f456c90731f42/aiohttp-3.11.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c2eaa145bb36b33af1ff2860820ba0589e165be4ab63a49aebfd0981c173b66", size = 457836 }, - { url = "https://files.pythonhosted.org/packages/49/7b/55b65af9ef48b9b811c91ff8b5b9de9650c71147f10523e278d297750bc8/aiohttp-3.11.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d518ce32179f7e2096bf4e3e8438cf445f05fedd597f252de9f54c728574756", size = 1690978 }, - { url = "https://files.pythonhosted.org/packages/a2/5a/3f8938c4f68ae400152b42742653477fc625d6bfe02e764f3521321c8442/aiohttp-3.11.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0700055a6e05c2f4711011a44364020d7a10fbbcd02fbf3e30e8f7e7fddc8717", size = 1745307 }, - { url = "https://files.pythonhosted.org/packages/b4/42/89b694a293333ef6f771c62da022163bcf44fb03d4824372d88e3dc12530/aiohttp-3.11.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8bd1cde83e4684324e6ee19adfc25fd649d04078179890be7b29f76b501de8e4", size = 1780692 }, - { url = "https://files.pythonhosted.org/packages/e2/ce/1a75384e01dd1bf546898b6062b1b5f7a59b6692ef802e4dd6db64fed264/aiohttp-3.11.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73b8870fe1c9a201b8c0d12c94fe781b918664766728783241a79e0468427e4f", size = 1676934 }, - { url = "https://files.pythonhosted.org/packages/a5/31/442483276e6c368ab5169797d9873b5875213cbcf7e74b95ad1c5003098a/aiohttp-3.11.18-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25557982dd36b9e32c0a3357f30804e80790ec2c4d20ac6bcc598533e04c6361", size = 1621190 }, - { url = "https://files.pythonhosted.org/packages/7b/83/90274bf12c079457966008a58831a99675265b6a34b505243e004b408934/aiohttp-3.11.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e889c9df381a2433802991288a61e5a19ceb4f61bd14f5c9fa165655dcb1fd1", size = 1658947 }, - { url = "https://files.pythonhosted.org/packages/91/c1/da9cee47a0350b78fdc93670ebe7ad74103011d7778ab4c382ca4883098d/aiohttp-3.11.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9ea345fda05bae217b6cce2acf3682ce3b13d0d16dd47d0de7080e5e21362421", size = 1654443 }, - { url = "https://files.pythonhosted.org/packages/c9/f2/73cbe18dc25d624f79a09448adfc4972f82ed6088759ddcf783cd201956c/aiohttp-3.11.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9f26545b9940c4b46f0a9388fd04ee3ad7064c4017b5a334dd450f616396590e", size = 1644169 }, - { url = "https://files.pythonhosted.org/packages/5b/32/970b0a196c4dccb1b0cfa5b4dc3b20f63d76f1c608f41001a84b2fd23c3d/aiohttp-3.11.18-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3a621d85e85dccabd700294494d7179ed1590b6d07a35709bb9bd608c7f5dd1d", size = 1728532 }, - { url = "https://files.pythonhosted.org/packages/0b/50/b1dc810a41918d2ea9574e74125eb053063bc5e14aba2d98966f7d734da0/aiohttp-3.11.18-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9c23fd8d08eb9c2af3faeedc8c56e134acdaf36e2117ee059d7defa655130e5f", size = 1750310 }, - { url = "https://files.pythonhosted.org/packages/95/24/39271f5990b35ff32179cc95537e92499d3791ae82af7dcf562be785cd15/aiohttp-3.11.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9e6b0e519067caa4fd7fb72e3e8002d16a68e84e62e7291092a5433763dc0dd", size = 1691580 }, - { url = "https://files.pythonhosted.org/packages/6b/78/75d0353feb77f041460564f12fe58e456436bbc00cbbf5d676dbf0038cc2/aiohttp-3.11.18-cp311-cp311-win32.whl", hash = "sha256:122f3e739f6607e5e4c6a2f8562a6f476192a682a52bda8b4c6d4254e1138f4d", size = 417565 }, - { url = "https://files.pythonhosted.org/packages/ed/97/b912dcb654634a813f8518de359364dfc45976f822116e725dc80a688eee/aiohttp-3.11.18-cp311-cp311-win_amd64.whl", hash = "sha256:e6f3c0a3a1e73e88af384b2e8a0b9f4fb73245afd47589df2afcab6b638fa0e6", size = 443652 }, - { url = "https://files.pythonhosted.org/packages/b5/d2/5bc436f42bf4745c55f33e1e6a2d69e77075d3e768e3d1a34f96ee5298aa/aiohttp-3.11.18-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:63d71eceb9cad35d47d71f78edac41fcd01ff10cacaa64e473d1aec13fa02df2", size = 706671 }, - { url = "https://files.pythonhosted.org/packages/fe/d0/2dbabecc4e078c0474abb40536bbde717fb2e39962f41c5fc7a216b18ea7/aiohttp-3.11.18-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d1929da615840969929e8878d7951b31afe0bac883d84418f92e5755d7b49508", size = 466169 }, - { url = "https://files.pythonhosted.org/packages/70/84/19edcf0b22933932faa6e0be0d933a27bd173da02dc125b7354dff4d8da4/aiohttp-3.11.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d0aebeb2392f19b184e3fdd9e651b0e39cd0f195cdb93328bd124a1d455cd0e", size = 457554 }, - { url = "https://files.pythonhosted.org/packages/32/d0/e8d1f034ae5624a0f21e4fb3feff79342ce631f3a4d26bd3e58b31ef033b/aiohttp-3.11.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3849ead845e8444f7331c284132ab314b4dac43bfae1e3cf350906d4fff4620f", size = 1690154 }, - { url = "https://files.pythonhosted.org/packages/16/de/2f9dbe2ac6f38f8495562077131888e0d2897e3798a0ff3adda766b04a34/aiohttp-3.11.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e8452ad6b2863709f8b3d615955aa0807bc093c34b8e25b3b52097fe421cb7f", size = 1733402 }, - { url = "https://files.pythonhosted.org/packages/e0/04/bd2870e1e9aef990d14b6df2a695f17807baf5c85a4c187a492bda569571/aiohttp-3.11.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b8d2b42073611c860a37f718b3d61ae8b4c2b124b2e776e2c10619d920350ec", size = 1783958 }, - { url = "https://files.pythonhosted.org/packages/23/06/4203ffa2beb5bedb07f0da0f79b7d9039d1c33f522e0d1a2d5b6218e6f2e/aiohttp-3.11.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fbf91f6a0ac317c0a07eb328a1384941872f6761f2e6f7208b63c4cc0a7ff6", size = 1695288 }, - { url = "https://files.pythonhosted.org/packages/30/b2/e2285dda065d9f29ab4b23d8bcc81eb881db512afb38a3f5247b191be36c/aiohttp-3.11.18-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ff5625413fec55216da5eaa011cf6b0a2ed67a565914a212a51aa3755b0009", size = 1618871 }, - { url = "https://files.pythonhosted.org/packages/57/e0/88f2987885d4b646de2036f7296ebea9268fdbf27476da551c1a7c158bc0/aiohttp-3.11.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f33a92a2fde08e8c6b0c61815521324fc1612f397abf96eed86b8e31618fdb4", size = 1646262 }, - { url = "https://files.pythonhosted.org/packages/e0/19/4d2da508b4c587e7472a032290b2981f7caeca82b4354e19ab3df2f51d56/aiohttp-3.11.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:11d5391946605f445ddafda5eab11caf310f90cdda1fd99865564e3164f5cff9", size = 1677431 }, - { url = "https://files.pythonhosted.org/packages/eb/ae/047473ea50150a41440f3265f53db1738870b5a1e5406ece561ca61a3bf4/aiohttp-3.11.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3cc314245deb311364884e44242e00c18b5896e4fe6d5f942e7ad7e4cb640adb", size = 1637430 }, - { url = "https://files.pythonhosted.org/packages/11/32/c6d1e3748077ce7ee13745fae33e5cb1dac3e3b8f8787bf738a93c94a7d2/aiohttp-3.11.18-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0f421843b0f70740772228b9e8093289924359d306530bcd3926f39acbe1adda", size = 1703342 }, - { url = "https://files.pythonhosted.org/packages/c5/1d/a3b57bfdbe285f0d45572d6d8f534fd58761da3e9cbc3098372565005606/aiohttp-3.11.18-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e220e7562467dc8d589e31c1acd13438d82c03d7f385c9cd41a3f6d1d15807c1", size = 1740600 }, - { url = "https://files.pythonhosted.org/packages/a5/71/f9cd2fed33fa2b7ce4d412fb7876547abb821d5b5520787d159d0748321d/aiohttp-3.11.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ab2ef72f8605046115bc9aa8e9d14fd49086d405855f40b79ed9e5c1f9f4faea", size = 1695131 }, - { url = "https://files.pythonhosted.org/packages/97/97/d1248cd6d02b9de6aa514793d0dcb20099f0ec47ae71a933290116c070c5/aiohttp-3.11.18-cp312-cp312-win32.whl", hash = "sha256:12a62691eb5aac58d65200c7ae94d73e8a65c331c3a86a2e9670927e94339ee8", size = 412442 }, - { url = "https://files.pythonhosted.org/packages/33/9a/e34e65506e06427b111e19218a99abf627638a9703f4b8bcc3e3021277ed/aiohttp-3.11.18-cp312-cp312-win_amd64.whl", hash = "sha256:364329f319c499128fd5cd2d1c31c44f234c58f9b96cc57f743d16ec4f3238c8", size = 439444 }, +sdist = { url = "https://files.pythonhosted.org/packages/eb/62/95588e933dfea06a3af0332990bd19f6768f8f37fa4c0fe33fe4c55cf9d0/aiohttp-3.12.7.tar.gz", hash = "sha256:08bf55b216c779eddb6e41c1841c17d7ddd12776c7d7b36051c0a292a9ca828e", size = 7806530 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/19/37560cc111d6fd95ff6c4bd14445e3c629269fce406c89cc7a69a2865ecf/aiohttp-3.12.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:388b5947aa6931ef4ce3ed4edde6853e84980677886992cfadcf733dd06eed63", size = 707169 }, + { url = "https://files.pythonhosted.org/packages/b9/18/29bbefb094f81a687473c1d31391bf8a4c48c7b5b8559c3679fc14e67597/aiohttp-3.12.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9ed5af1cce257cca27a3e920b003b3b397f63418a203064b7d804ea3b45782af", size = 479443 }, + { url = "https://files.pythonhosted.org/packages/cf/7d/119f3e012c75a3fe38f86ac1d77f1452779e0e940770d5827d4e62aa5655/aiohttp-3.12.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f466ae8f9c02993b7d167be685bdbeb527cf254a3cfcc757697e0e336399d0a2", size = 467706 }, + { url = "https://files.pythonhosted.org/packages/83/f1/f61d8573d648e17347ab9a112063e4363664b5b6100792467fbb26028bde/aiohttp-3.12.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2be095a420a9f9a12eff343d877ae180dd919238b539431af08cef929e874759", size = 1737902 }, + { url = "https://files.pythonhosted.org/packages/4b/f8/7a8a000bc63de3c79aaa8f03b0784e29e9982276f4579c5e2e56d560e403/aiohttp-3.12.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b058cf2ba6adba699960d7bc403411c8a99ab5d3e5ea3eb01473638ae7d1a30e", size = 1686569 }, + { url = "https://files.pythonhosted.org/packages/5c/4e/29a5b35ca9a598f51dc7deff4e8403bf813988f30a8b250e25a8442641b7/aiohttp-3.12.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b6a660163b055686dbb0acc961978fd14537eba5d9da6cbdb4dced7a8d3be1a", size = 1785359 }, + { url = "https://files.pythonhosted.org/packages/f9/36/0521398a69c40ac24c659b130597e2544cde1d7dd00291b8a6206bb552d0/aiohttp-3.12.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d741923905f267ad5d5c8f86a56f9d2beac9f32a36c217c5d9ef65cd74fd8ca0", size = 1824408 }, + { url = "https://files.pythonhosted.org/packages/c1/41/79506d76da96399b6b700acbe10b14291547a3b49a1cc7ed2c5edaa199ce/aiohttp-3.12.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:519f5454b6018158ae0e789b8f6a88726c47dd680982eb318ef3ca4dee727314", size = 1726867 }, + { url = "https://files.pythonhosted.org/packages/32/d1/d59ed16962934b46c7569d04af2dc9638a38ae5812680b9d6c7ee42d770e/aiohttp-3.12.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4eebfe470e22cc4b374d7e32c07e96d777a5c0fa51f3824de68e697da037ec", size = 1663943 }, + { url = "https://files.pythonhosted.org/packages/15/d5/971d1b277e6a3d5b679f0c9ba076c343a5125ea2eacc51c23ea7d875d43a/aiohttp-3.12.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:74ff39445f94923cf595e9e6dd602ecbe66b12364e2207e61342b8834417f8da", size = 1712217 }, + { url = "https://files.pythonhosted.org/packages/e1/9c/c21fd0ba87772f3d1d43cdbfcfd40fe29f37d36a5d73997a8a4d4d1485c3/aiohttp-3.12.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:77cb9dba16486ecfeac8076763600b9714941e0ff696e53a30e8d408d9a196ca", size = 1707375 }, + { url = "https://files.pythonhosted.org/packages/85/48/bb97ef3a694df852b70e6f5c1aaf3621a3a26b35f0a0d90481f3fdb1ce8b/aiohttp-3.12.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a7b3b9cbe83e3918a1918b0de274884f17b64224c1c9210a6fb0f7c10d246636", size = 1687561 }, + { url = "https://files.pythonhosted.org/packages/d5/75/0b85f30ba9eb1dbdb5d3a53d3a0db29990220f69187acb24d06903686c5d/aiohttp-3.12.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6055f53c70938498884e71ca966abe8e9e7558489e13a7e40b6384dee7230d1d", size = 1781163 }, + { url = "https://files.pythonhosted.org/packages/92/51/6350a4c485c7d2fb794101d46085c3830485ec1c37738d8af6c9c5ed8e1a/aiohttp-3.12.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8493a42d5b2a736c6804239b985feebeea1c60f8fcb46a3607d6dce3c1a42b12", size = 1801624 }, + { url = "https://files.pythonhosted.org/packages/4f/dd/6a75eaaac93b5552090e42c38a576062028ce4af50f0b50ac550332d332c/aiohttp-3.12.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:372f2237cade45f563d973c2a913895f2699a892c0eb11c55c6880b6f0acf219", size = 1714679 }, + { url = "https://files.pythonhosted.org/packages/de/ad/0574964387d8eed7fcd0c2fe6ef20c4affe0b265c710938d5fffdb3776b5/aiohttp-3.12.7-cp311-cp311-win32.whl", hash = "sha256:41f686749a099b507563a5c0cb4fd77367b05448a2c1758784ad506a28e9e579", size = 424709 }, + { url = "https://files.pythonhosted.org/packages/4f/ab/6b82b43abb0990e4452aaef509cf1403ab50c04b5c090f92fb1b255fb319/aiohttp-3.12.7-cp311-cp311-win_amd64.whl", hash = "sha256:7a3691583470d4397aca70fbf8e0f0778b63a2c2a6a23263bdeeb68395972f29", size = 449100 }, + { url = "https://files.pythonhosted.org/packages/5d/65/0bd8ccbffa33ee69db9f5c43f3f62fb8b600b607388e9a8deab8962d0523/aiohttp-3.12.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9b9345918f5b5156a5712c37d1d331baf320df67547ea032a49a609b773c3606", size = 698263 }, + { url = "https://files.pythonhosted.org/packages/99/64/a48a8abc4e684fb447d1f7b61e7adcb19865b91e20b50595f49b2942fbb3/aiohttp-3.12.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3091b4883f405dbabeb9ea821a25dec16d03a51c3e0d2752fc3ab48b652bf196", size = 472877 }, + { url = "https://files.pythonhosted.org/packages/7d/e4/994bc56a7d7733e9cd1f45db8b656e78d51d7a61cefff8043ec4f7d4a23f/aiohttp-3.12.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:97fd97abd4cf199eff4041d0346a7dc68b60deab177f01de87283be513ffc3ab", size = 465716 }, + { url = "https://files.pythonhosted.org/packages/39/b0/bddc489288a0e3b05fa05387db9caebc38577204a17db0d5428abae524ba/aiohttp-3.12.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a5938973105cd5ff17176e8cb36bc19cac7c82ae7c58c0dbd7e023972d0c708", size = 1712513 }, + { url = "https://files.pythonhosted.org/packages/4d/4a/c06d3ce0dc5f96338cc8d18da57d74608585a3751234eeef5952e4f48ade/aiohttp-3.12.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e506ae5c4c05d1a1e87edd64b994cea2d49385d41d32e1c6be8764f31cf2245c", size = 1695167 }, + { url = "https://files.pythonhosted.org/packages/79/ec/e847fdfe2b1c1f1a2b0ba5343a9b2bd033a0545f8eaf1f7894a6614473ae/aiohttp-3.12.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b780b402e6361c4cfcec252580f5ecdd86cb68376520ac34748d3f8b262dd598", size = 1750261 }, + { url = "https://files.pythonhosted.org/packages/2c/5e/b832ff59737d99cc5ae51b737c52976d19990ccee922ba6fe811f615e7f9/aiohttp-3.12.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf981bbfb7ff2ebc1b3bfae49d2efe2c51ca1cf3d90867f47c310df65398e85e", size = 1796416 }, + { url = "https://files.pythonhosted.org/packages/e0/ff/51ae87efce9b53aafd384179f58923bf178f561897cf80054a440fdf8363/aiohttp-3.12.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94f98e0e5a49f89b252e115844f756c04fc8050f38252a32a3dd994ce8121f10", size = 1715855 }, + { url = "https://files.pythonhosted.org/packages/b1/54/5a77116498f84d2503f5588e687eccfa43a85aa2450bc195ee6e5bb75695/aiohttp-3.12.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:410e96cc6824fc4ced9703fb2ac2d06c6190d21fc6f5b588f62b1918628449c1", size = 1631656 }, + { url = "https://files.pythonhosted.org/packages/46/34/554220592f8ade7f3cabebfb9325e95078f842140f293ced3ab977fd13ec/aiohttp-3.12.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:43e93987fe9df4349db8deae7c391695538c35e4ba893133c7e823234f6e4537", size = 1692718 }, + { url = "https://files.pythonhosted.org/packages/ff/9d/ae7103bb8c73c3521e38ae8cde301ddc937024b1681ce134bb1ef01be7d0/aiohttp-3.12.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cb3f3dcb59f3e16819a1c7d3fa32e7b87255b661c1e139a1b5940bde270704ab", size = 1714171 }, + { url = "https://files.pythonhosted.org/packages/5d/4d/9b8b8f362e36392939019340321f7efcc1807bb2c4cdea8eb1019d3398ff/aiohttp-3.12.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4a46fe4a4c66b2712059e48a8384eb93565fbe3251af4844860fed846ef4ca75", size = 1654822 }, + { url = "https://files.pythonhosted.org/packages/48/30/0ca82df423ee346206bc167852c825cd210c11d2f1fa0064a2a55d7f60d5/aiohttp-3.12.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ad01793164661af70918490ef8efc2c09df7a3c686b6c84ca90a2d69cdbc3911", size = 1734385 }, + { url = "https://files.pythonhosted.org/packages/43/bd/96d12318c0f82ac8323bd4459ee26291ad220f688988077a21e538b0872c/aiohttp-3.12.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e85c6833be3f49cead2e7bc79080e5c18d6dab9af32226ab5a01dc20c523e7d9", size = 1762356 }, + { url = "https://files.pythonhosted.org/packages/6c/39/7a9b706bf42f293415584d60cf35e80d0558929ab70e72cb40b747f0dfc7/aiohttp-3.12.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c9f52149d8249566e72c50c7985c2345521b3b78f84aa86f6f492cd50b14793", size = 1721970 }, + { url = "https://files.pythonhosted.org/packages/19/f2/8899367a52dec8100f43036e5a792cfdbae317bf3a80549da90290083ff4/aiohttp-3.12.7-cp312-cp312-win32.whl", hash = "sha256:0e1c33ac0f6a396bcefe9c1d52c9d38a051861885a5c102ca5c8298aba0108fa", size = 419443 }, + { url = "https://files.pythonhosted.org/packages/e8/34/ad5225b4edbcc23496537011d67ef1a147c03205c07340f4a50993b219b9/aiohttp-3.12.7-cp312-cp312-win_amd64.whl", hash = "sha256:b4aed5233a9d13e34e8624ecb798533aa2da97e7048cc69671b7a6d7a2efe7e8", size = 445544 }, ] [[package]] @@ -109,16 +111,16 @@ wheels = [ [[package]] name = "alembic" -version = "1.15.2" +version = "1.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mako" }, { name = "sqlalchemy" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e6/57/e314c31b261d1e8a5a5f1908065b4ff98270a778ce7579bd4254477209a7/alembic-1.15.2.tar.gz", hash = "sha256:1c72391bbdeffccfe317eefba686cb9a3c078005478885413b95c3b26c57a8a7", size = 1925573 } +sdist = { url = "https://files.pythonhosted.org/packages/20/89/bfb4fe86e3fc3972d35431af7bedbc60fa606e8b17196704a1747f7aa4c3/alembic-1.16.1.tar.gz", hash = "sha256:43d37ba24b3d17bc1eb1024fe0f51cd1dc95aeb5464594a02c6bb9ca9864bfa4", size = 1955006 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/18/d89a443ed1ab9bcda16264716f809c663866d4ca8de218aa78fd50b38ead/alembic-1.15.2-py3-none-any.whl", hash = "sha256:2e76bd916d547f6900ec4bb5a90aeac1485d2c92536923d0b138c02b126edc53", size = 231911 }, + { url = "https://files.pythonhosted.org/packages/31/59/565286efff3692c5716c212202af61466480f6357c4ae3089d4453bff1f3/alembic-1.16.1-py3-none-any.whl", hash = "sha256:0cdd48acada30d93aa1035767d67dff25702f8de74d7c3919f2e8492c8db2e67", size = 242488 }, ] [[package]] @@ -444,16 +446,16 @@ wheels = [ [[package]] name = "bce-python-sdk" -version = "0.9.29" +version = "0.9.35" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "future" }, { name = "pycryptodome" }, { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/51/f6/3237811b0a9fd79ba9fcf4d13085f1a1ea19fee43b0cbb24189661d787d5/bce_python_sdk-0.9.29.tar.gz", hash = "sha256:326fbd50d57bf6d2fc21d58f589b069e0e84fc0a8733be9575c109293ab08cc4", size = 246628 } +sdist = { url = "https://files.pythonhosted.org/packages/c6/91/c218750fd515fef10d197a2385a81a5f3504d30637fc1268bafa53cc2837/bce_python_sdk-0.9.35.tar.gz", hash = "sha256:024a2b5cd086707c866225cf8631fa126edbccfdd5bc3c8a83fe2ea9aa768bf5", size = 247844 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/60/b3247bae81d5ecde1a88430ffe8c57ea3f7212c6a6670b540f7d34d2c625/bce_python_sdk-0.9.29-py3-none-any.whl", hash = "sha256:6518dc0ada422acd1841eeabcb7f89cfc07e3bb1a4be3c75945cab953907b555", size = 343584 }, + { url = "https://files.pythonhosted.org/packages/28/81/f574f6b300927a63596fa8e5081f5c0ad66d5cc99004d70d63c523f42ff8/bce_python_sdk-0.9.35-py3-none-any.whl", hash = "sha256:08c1575a0f2ec04b2fc17063fe6e47e1aab48e3bca1f26181cb8bed5528fa5de", size = 344813 }, ] [[package]] @@ -542,16 +544,16 @@ wheels = [ [[package]] name = "boto3-stubs" -version = "1.38.20" +version = "1.38.28" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore-stubs" }, { name = "types-s3transfer" }, { name = "typing-extensions", marker = "python_full_version < '3.12'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4e/89/824fb0a9bebf9f1d6df70bb145f8e9c24fc4d918d4050b5d4dca075cc292/boto3_stubs-1.38.20.tar.gz", hash = "sha256:7f1d7bfff7355eb4d17e7984fbf27f44709cd8484abb54bd6ba34ec73a552605", size = 99063 } +sdist = { url = "https://files.pythonhosted.org/packages/7b/dc/c4b318bdf66ff4973d3cbf0f218e47bdf558b94d921c8ff27d401e8ca4f9/boto3_stubs-1.38.28.tar.gz", hash = "sha256:fae8e009ea4d810b77e49d88247183b5d8d153bf268ebde8b4abdf58a701802f", size = 99065 } wheels = [ - { url = "https://files.pythonhosted.org/packages/57/69/cfc45dfce3b4ea417f9aec708ade1eda7f280fe8ae7feca796b036619587/boto3_stubs-1.38.20-py3-none-any.whl", hash = "sha256:5406da868980a3854cc9b57db150c6f2e39a4fe4a58f2872e61ac5a3d46f734e", size = 68667 }, + { url = "https://files.pythonhosted.org/packages/8b/4a/d70ef76080e0d37e45d07d65801a6680f5bc1d156333a4e5d0ca6103d45f/boto3_stubs-1.38.28-py3-none-any.whl", hash = "sha256:accd8c0943a8d960c5c2d4a7aa661fd43e842893e76adf1b5b163c02f4f62537", size = 68668 }, ] [package.optional-dependencies] @@ -575,39 +577,39 @@ wheels = [ [[package]] name = "botocore-stubs" -version = "1.38.19" +version = "1.38.28" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-awscrt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/70/6204c97f8d8362364f11c16085566abdcaa114c264d3a4d709ff697b203b/botocore_stubs-1.38.19.tar.gz", hash = "sha256:84f67a42bb240a8ea0c5fe4f05d497cc411177db600bc7012182e499ac24bf19", size = 42269 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/0e/a47d392ee3fbd444a628f1b7257affc0a13c45e8742de4eb31fa4e2758f2/botocore_stubs-1.38.28.tar.gz", hash = "sha256:b9549050b81051bdbb91966323d6a2b6c5c78ca8dcc328e16dfc44b765be39be", size = 42312 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/ce/28b143452c22b678678d832bf8b41218e3d319bf94062b48c28fe5d81163/botocore_stubs-1.38.19-py3-none-any.whl", hash = "sha256:66fd7d231c21134a12acbe313ef7a6b152cbf9bfd7bfa12a62f8c33e94737e26", size = 65603 }, + { url = "https://files.pythonhosted.org/packages/6f/3d/26c1a62b379f0dd401798f9f8f9331ac40f3c3917c34b5eed3ed0b85e2b0/botocore_stubs-1.38.28-py3-none-any.whl", hash = "sha256:9151ced682edb44b28202d268f4dc5ef5534be8b592b87e07ce4c99650818bce", size = 65629 }, ] [[package]] name = "bottleneck" -version = "1.4.2" +version = "1.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/61/9fb34409d58f04e1929da41666a055c36f9495903ff669b80c893bdee65f/bottleneck-1.4.2.tar.gz", hash = "sha256:fa8e8e1799dea5483ce6669462660f9d9a95649f6f98a80d315b84ec89f449f4", size = 103563 } +sdist = { url = "https://files.pythonhosted.org/packages/80/82/dd20e69b97b9072ed2d26cc95c0a573461986bf62f7fde7ac59143490918/bottleneck-1.5.0.tar.gz", hash = "sha256:c860242cf20e69d5aab2ec3c5d6c8c2a15f19e4b25b28b8fca2c2a12cefae9d8", size = 104177 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b8/31a1cc8279bf11a60c04b844a42666927307a47bb48964cbd92ec9f40e3e/Bottleneck-1.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6902ebf3e85315b481bc084f10c5770f8240275ad1e039ac69c7c8d2013b040", size = 98565 }, - { url = "https://files.pythonhosted.org/packages/16/64/09d72babae7cc29341c52f2e9381066672743d4f797c86b1e735205d5fc8/Bottleneck-1.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2fd34b9b490204f95288f0dd35d37042486a95029617246c88c0f94a0ab49fe", size = 364986 }, - { url = "https://files.pythonhosted.org/packages/7e/d6/39e957e9df9ab16df9c531e8ddf71594877063d27aa036dd105b66d3b3b3/Bottleneck-1.4.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:122845e3106c85465551d4a9a3777841347cfedfbebb3aa985cca110e07030b1", size = 360256 }, - { url = "https://files.pythonhosted.org/packages/ff/cb/d287febe0e6504194ba94cf4a6d80df66a0031ca33a32b30f00c030238cc/Bottleneck-1.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1f61658ebdf5a178298544336b65020730bf86cc092dab5f6579a99a86bd888b", size = 369507 }, - { url = "https://files.pythonhosted.org/packages/dc/1e/9310f058ddee71798a76ab15c5c1ad71f0a5c3c6348f7faab9b6da038484/Bottleneck-1.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7c7d29c044a3511b36fd744503c3e697e279c273a8477a6d91a2831d04fd19e0", size = 360282 }, - { url = "https://files.pythonhosted.org/packages/96/cb/c1f2a37e86e9fa47845259f0a8f32d550f7f27b908432369de055be9f7c4/Bottleneck-1.4.2-cp311-cp311-win32.whl", hash = "sha256:c663cbba8f52011fd82ee08c6a85c93b34b19e0e7ebba322d2d67809f34e0597", size = 106936 }, - { url = "https://files.pythonhosted.org/packages/d3/eb/3fd23404bbc612cf9e4883c3c2b359bd14528e234d5c40bb29bcfd591ef8/Bottleneck-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:89651ef18c06616850203bf8875c958c5d316ea48d8ba60d9b450199d39ae391", size = 111617 }, - { url = "https://files.pythonhosted.org/packages/d2/26/6f5124e31a67f75e2a3b9239cc382145326e91fc45e7d7bc9ebffa05fdfa/Bottleneck-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a74ddd0417f42eeaba37375f0fc065b28451e0fba45cb2f99e88880b10b3fa43", size = 98681 }, - { url = "https://files.pythonhosted.org/packages/c4/93/e100b6eda77f2aecf5f16157b8c04dd3463913ba188b582650cd77ccf42b/Bottleneck-1.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:070d22f2f62ab81297380a89492cca931e4d9443fa4b84c2baeb52db09c3b1b4", size = 365422 }, - { url = "https://files.pythonhosted.org/packages/82/2b/c6fea2bb048d04c13b8564052818a198d50ce58d5f439ec69c2b0c458703/Bottleneck-1.4.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fc4e7645bd425c05e05acd5541e9e09cb4179e71164e862f082561bf4509eac", size = 361844 }, - { url = "https://files.pythonhosted.org/packages/8f/4c/811475885bd60cf0cb28822568d0c0c3c7d7de4fbccd2ebb66863e7dc726/Bottleneck-1.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:037315c56605128a39f77d19af6a6019dc8c21a63694a4bfef3c026ed963be2e", size = 370369 }, - { url = "https://files.pythonhosted.org/packages/fd/ee/0a8157e6bbd2168bf6171811534a5a73a35f54c453dd7d86a323773b5bd7/Bottleneck-1.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:99778329331d5fae8df19772a019e8b73ba4d9d1650f110cd995ab7657114db0", size = 361786 }, - { url = "https://files.pythonhosted.org/packages/fa/6b/e8fda0510b8fa0f3f9a3586efc941abe9d546198e95ae5690c3c83370b36/Bottleneck-1.4.2-cp312-cp312-win32.whl", hash = "sha256:7363b3c8ce6ca433779cd7e96bcb94c0e516dcacadff0011adcbf0b3ac86bc9d", size = 107149 }, - { url = "https://files.pythonhosted.org/packages/22/25/908b75a329a05b82d717661aa95a1968d9dae0e68c654d5e16bfe0d6fbb6/Bottleneck-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:48c6b9d9287c4102b803fcb01ae66ae7ef6b310b711b4b7b7e23bf952894dc05", size = 111766 }, + { url = "https://files.pythonhosted.org/packages/fd/5e/d66b2487c12fa3343013ac87a03bcefbeacf5f13ffa4ad56bb4bce319d09/bottleneck-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9be5dfdf1a662d1d4423d7b7e8dd9a1b7046dcc2ce67b6e94a31d1cc57a8558f", size = 99536 }, + { url = "https://files.pythonhosted.org/packages/28/24/e7030fe27c7a9eb9cc8c86a4d74a7422d2c3e3466aecdf658617bea40491/bottleneck-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16fead35c0b5d307815997eef67d03c2151f255ca889e0fc3d68703f41aa5302", size = 357134 }, + { url = "https://files.pythonhosted.org/packages/d0/ce/91b0514a7ac456d934ebd90f0cae2314302f33c16e9489c99a4f496b1cff/bottleneck-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:049162927cf802208cc8691fb99b108afe74656cdc96b9e2067cf56cb9d84056", size = 361243 }, + { url = "https://files.pythonhosted.org/packages/be/f7/1a41889a6c0863b9f6236c14182bfb5f37c964e791b90ba721450817fc24/bottleneck-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2f5e863a4fdaf9c85416789aeb333d1cdd3603037fd854ad58b0e2ac73be16cf", size = 361326 }, + { url = "https://files.pythonhosted.org/packages/d3/e8/d4772b5321cf62b53c792253e38db1f6beee4f2de81e65bce5a6fe78df8e/bottleneck-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8d123762f78717fc35ecf10cad45d08273fcb12ab40b3c847190b83fec236f03", size = 371849 }, + { url = "https://files.pythonhosted.org/packages/29/dc/f88f6d476d7a3d6bd92f6e66f814d0bf088be20f0c6f716caa2a2ca02e82/bottleneck-1.5.0-cp311-cp311-win32.whl", hash = "sha256:07c2c1aa39917b5c9be77e85791aa598e8b2c00f8597a198b93628bbfde72a3f", size = 107710 }, + { url = "https://files.pythonhosted.org/packages/17/03/f89a2eff4f919a7c98433df3be6fd9787c72966a36be289ec180f505b2d5/bottleneck-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:80ef9eea2a92fc5a1c04734aa1bcf317253241062c962eaa6e7f123b583d0109", size = 112055 }, + { url = "https://files.pythonhosted.org/packages/8e/64/127e174cec548ab98bc0fa868b4f5d3ae5276e25c856d31d235d83d885a8/bottleneck-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dbb0f0d38feda63050aa253cf9435e81a0ecfac954b0df84896636be9eabd9b6", size = 99640 }, + { url = "https://files.pythonhosted.org/packages/59/89/6e0b6463a36fd4771a9227d22ea904f892b80d95154399dd3e89fb6001f8/bottleneck-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:613165ce39bf6bd80f5307da0f05842ba534b213a89526f1eba82ea0099592fc", size = 358009 }, + { url = "https://files.pythonhosted.org/packages/f7/d6/7d1795a4a9e6383d3710a94c44010c7f2a8ba58cb5f2d9e2834a1c179afe/bottleneck-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f218e4dae6511180dcc4f06d8300e0c81e7f3df382091f464c5a919d289fab8e", size = 362875 }, + { url = "https://files.pythonhosted.org/packages/2b/1b/bab35ef291b9379a97e2fb986ce75f32eda38a47fc4954177b43590ee85e/bottleneck-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3886799cceb271eb67d057f6ecb13fb4582bda17a3b13b4fa0334638c59637c6", size = 361194 }, + { url = "https://files.pythonhosted.org/packages/d5/f3/a416fed726b81d2093578bc2112077f011c9f57b31e7ff3a1a9b00cce3d3/bottleneck-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dc8d553d4bf033d3e025cd32d4c034d2daf10709e31ced3909811d1c843e451c", size = 373253 }, + { url = "https://files.pythonhosted.org/packages/0a/40/c372f9e59b3ce340d170fbdc24c12df3d2b3c22c4809b149b7129044180b/bottleneck-1.5.0-cp312-cp312-win32.whl", hash = "sha256:0dca825048a3076f34c4a35409e3277b31ceeb3cbb117bbe2a13ff5c214bcabc", size = 107915 }, + { url = "https://files.pythonhosted.org/packages/28/5a/57571a3cd4e356bbd636bb2225fbe916f29adc2235ba3dc77cd4085c91c8/bottleneck-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f26005740e6ef6013eba8a48241606a963e862a601671eab064b7835cd12ef3d", size = 112148 }, ] [[package]] @@ -706,7 +708,7 @@ wheels = [ [[package]] name = "celery" -version = "5.5.2" +version = "5.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "billiard" }, @@ -718,9 +720,9 @@ dependencies = [ { name = "python-dateutil" }, { name = "vine" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/03/5d9c6c449248958f1a5870e633a29d7419ff3724c452a98ffd22688a1a6a/celery-5.5.2.tar.gz", hash = "sha256:4d6930f354f9d29295425d7a37261245c74a32807c45d764bedc286afd0e724e", size = 1666892 } +sdist = { url = "https://files.pythonhosted.org/packages/bb/7d/6c289f407d219ba36d8b384b42489ebdd0c84ce9c413875a8aae0c85f35b/celery-5.5.3.tar.gz", hash = "sha256:6c972ae7968c2b5281227f01c3a3f984037d21c5129d07bf3550cc2afc6b10a5", size = 1667144 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/94/8e825ac1cf59d45d20c4345d4461e6b5263ae475f708d047c3dad0ac6401/celery-5.5.2-py3-none-any.whl", hash = "sha256:54425a067afdc88b57cd8d94ed4af2ffaf13ab8c7680041ac2c4ac44357bdf4c", size = 438626 }, + { url = "https://files.pythonhosted.org/packages/c9/af/0dcccc7fdcdf170f9a1585e5e96b6fb0ba1749ef6be8c89a6202284759bd/celery-5.5.3-py3-none-any.whl", hash = "sha256:0b5761a07057acee94694464ca482416b959568904c9dfa41ce8413a7d65d525", size = 438775 }, ] [[package]] @@ -869,25 +871,16 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5f/7a/10bf5dc92d13cc03230190fcc5016a0b138d99e5b36b8b89ee0fe1680e10/chromadb-0.5.20-py3-none-any.whl", hash = "sha256:9550ba1b6dce911e35cac2568b301badf4b42f457b99a432bdeec2b6b9dd3680", size = 617884 }, ] -[[package]] -name = "circuitbreaker" -version = "2.1.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/ac/de7a92c4ed39cba31fe5ad9203b76a25ca67c530797f6bb420fff5f65ccb/circuitbreaker-2.1.3.tar.gz", hash = "sha256:1a4baee510f7bea3c91b194dcce7c07805fe96c4423ed5594b75af438531d084", size = 10787 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/34/15f08edd4628f65217de1fc3c1a27c82e46fe357d60c217fc9881e12ebcc/circuitbreaker-2.1.3-py3-none-any.whl", hash = "sha256:87ba6a3ed03fdc7032bc175561c2b04d52ade9d5faf94ca2b035fbdc5e6b1dd1", size = 7737 }, -] - [[package]] name = "click" -version = "8.2.0" +version = "8.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cd/0f/62ca20172d4f87d93cf89665fbaedcd560ac48b465bd1d92bfc7ea6b0a41/click-8.2.0.tar.gz", hash = "sha256:f5452aeddd9988eefa20f90f05ab66f17fce1ee2a36907fd30b05bbb5953814d", size = 235857 } +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/58/1f37bf81e3c689cc74ffa42102fa8915b59085f54a6e4a80bc6265c0f6bf/click-8.2.0-py3-none-any.whl", hash = "sha256:6b303f0b2aa85f1cb4e5303078fadcbcd4e476f114fab9b5007005711839325c", size = 102156 }, + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215 }, ] [[package]] @@ -1024,22 +1017,22 @@ sdist = { url = "https://files.pythonhosted.org/packages/c4/f2/be99b41433b33a768 [[package]] name = "couchbase" -version = "4.3.5" +version = "4.3.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/6d/560ce2b7a93c6d90777008f39616e86bdf6c0f9bdcff685f7047d71786a6/couchbase-4.3.5.tar.gz", hash = "sha256:2e2f239b2959ece983195e3ee17a9142bc75b23b0f6733031198648a5f1107ed", size = 6514248 } +sdist = { url = "https://files.pythonhosted.org/packages/2f/70/7cf92b2443330e7a4b626a02fe15fbeb1531337d75e6ae6393294e960d18/couchbase-4.3.6.tar.gz", hash = "sha256:d58c5ccdad5d85fc026f328bf4190c4fc0041fdbe68ad900fb32fc5497c3f061", size = 6517695 } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8f/8d4e94893d1a1087bdf1045a055c44bfbfafc109dd193566f8f6216fbdcc/couchbase-4.3.5-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:21cb325b4a5b017581ee038dc2362865bcd59b3aa65685432a362f9f8e8f3276", size = 4774089 }, - { url = "https://files.pythonhosted.org/packages/fa/ff/00e02271cdb23968f523661b92988bd14e2e68a7c546fe3660efd2e0fc5a/couchbase-4.3.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5f063f79af8fe2425025ac9675e95bc914329db72f40adfd609451dcaf177920", size = 4295794 }, - { url = "https://files.pythonhosted.org/packages/38/15/f0ad47c6e5a2245121a70e687caab25dd080c4d24df2dc098aebd634121a/couchbase-4.3.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c28c05189c138408693d926211d80e0cb82fae02ac5e4619cb37efeb26349c1c", size = 4801822 }, - { url = "https://files.pythonhosted.org/packages/c8/58/9958caf475a3732d40557b62bfcc8bf1f3658338e80c17d7d8ceab05179b/couchbase-4.3.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:caf8f30cd1d587829685cffe575ec2b0f750a10611fe9f14e615070c1756079b", size = 5017314 }, - { url = "https://files.pythonhosted.org/packages/52/31/6f186553b4f58e7762d82950eb778deaf58fe48c8be58f7926e08ce3ee28/couchbase-4.3.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0aaef43bac983332e8bd8484a286a9576a878a95b4e5bfc6bf9c4aa8b3ff71b4", size = 5675942 }, - { url = "https://files.pythonhosted.org/packages/06/ff/70240653c27372c4da12a4dd5dfc3603e7c91d890014a9c1bc25c4053615/couchbase-4.3.5-cp311-cp311-win_amd64.whl", hash = "sha256:07deb48cd32e726088d2b2b93bb52fdca0b26e3e36b7d8b3728ea993a90b4327", size = 4013966 }, - { url = "https://files.pythonhosted.org/packages/50/e3/2f56064284d2687e58aedab57511636832cc9cd5380d379849ec65bf8819/couchbase-4.3.5-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:5c9f5754d7391ad3c53adb46a8b401bfd4e0db38aba707a5ed6daad295091afd", size = 4775392 }, - { url = "https://files.pythonhosted.org/packages/36/a1/8ec76a289d8e5941d252195de6190f86d7c6e67d8a5b4c949d7282c8176d/couchbase-4.3.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:92cea5d666d484c3801c2186ba2e0dd9df1bc654296c5862c94bf7a56e7e1e34", size = 4023876 }, - { url = "https://files.pythonhosted.org/packages/00/4b/ec60796cd22acfc5eb3d3fc638923b19639aa9463a7f7106e8f2d9a11929/couchbase-4.3.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f471b746cf13e9789de13fccd1ba4fbd3ae95e72710c3b07eb98cf8d72a5053b", size = 4803302 }, - { url = "https://files.pythonhosted.org/packages/39/5b/814b5a422ea153981e8894c32b0451fefe5e3bd95128b59fe9744df07a9f/couchbase-4.3.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80de6c8ddf39c4ee380d093fcf83a6300e837db8a6f60a8ddb7df6fcbb662595", size = 5022682 }, - { url = "https://files.pythonhosted.org/packages/26/1d/3cdd06a46c436bc2d8d14d57e994785783e809a37bb65ab3631dd1ca4fbd/couchbase-4.3.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9ce0c9e073a616cc6353ea93e9bac0fe6f79ff6df03fccf0c846f19b5ddf957b", size = 5675465 }, - { url = "https://files.pythonhosted.org/packages/0e/ec/2544932af7e118acbb6fe0b59163b4a8c8c72faec8fdb4bbeb062939b94c/couchbase-4.3.5-cp312-cp312-win_amd64.whl", hash = "sha256:b78f98001f40450ef1bbaf7d73fa28f0734e9bd72b38b96c18eb2090a09094fb", size = 4022539 }, + { url = "https://files.pythonhosted.org/packages/f3/0a/eae21d3a9331f7c93e8483f686e1bcb9e3b48f2ce98193beb0637a620926/couchbase-4.3.6-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:4c10fd26271c5630196b9bcc0dd7e17a45fa9c7e46ed5756e5690d125423160c", size = 4775710 }, + { url = "https://files.pythonhosted.org/packages/f6/98/0ca042a42f5807bbf8050f52fff39ebceebc7bea7e5897907758f3e1ad39/couchbase-4.3.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:811eee7a6013cea7b15a718e201ee1188df162c656d27c7882b618ab57a08f3a", size = 4020743 }, + { url = "https://files.pythonhosted.org/packages/f8/0f/c91407cb082d2322217e8f7ca4abb8eda016a81a4db5a74b7ac6b737597d/couchbase-4.3.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2fc177e0161beb1e6e8c4b9561efcb97c51aed55a77ee11836ca194d33ae22b7", size = 4796091 }, + { url = "https://files.pythonhosted.org/packages/8c/02/5567b660543828bdbbc68dcae080e388cb0be391aa8a97cce9d8c8a6c147/couchbase-4.3.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:02afb1c1edd6b215f702510412b5177ed609df8135930c23789bbc5901dd1b45", size = 5015684 }, + { url = "https://files.pythonhosted.org/packages/dc/d1/767908826d5bdd258addab26d7f1d21bc42bafbf5f30d1b556ace06295af/couchbase-4.3.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:594e9eb17bb76ba8e10eeee17a16aef897dd90d33c6771cf2b5b4091da415b32", size = 5673513 }, + { url = "https://files.pythonhosted.org/packages/f2/25/39ecde0a06692abce8bb0df4f15542933f05883647a1a57cdc7bbed9c77c/couchbase-4.3.6-cp311-cp311-win_amd64.whl", hash = "sha256:db22c56e38b8313f65807aa48309c8b8c7c44d5517b9ff1d8b4404d4740ec286", size = 4010728 }, + { url = "https://files.pythonhosted.org/packages/b1/55/c12b8f626de71363fbe30578f4a0de1b8bb41afbe7646ff8538c3b38ce2a/couchbase-4.3.6-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:a2ae13432b859f513485d4cee691e1e4fce4af23ed4218b9355874b146343f8c", size = 4693517 }, + { url = "https://files.pythonhosted.org/packages/a1/aa/2184934d283d99b34a004f577bf724d918278a2962781ca5690d4fa4b6c6/couchbase-4.3.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ea5ca7e34b5d023c8bab406211ab5d71e74a976ba25fa693b4f8e6c74f85aa2", size = 4022393 }, + { url = "https://files.pythonhosted.org/packages/80/29/ba6d3b205a51c04c270c1b56ea31da678b7edc565b35a34237ec2cfc708d/couchbase-4.3.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6eaca0a71fd8f9af4344b7d6474d7b74d1784ae9a658f6bc3751df5f9a4185ae", size = 4798396 }, + { url = "https://files.pythonhosted.org/packages/4a/94/d7d791808bd9064c01f965015ff40ee76e6bac10eaf2c73308023b9bdedf/couchbase-4.3.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0470378b986f69368caed6d668ac6530e635b0c1abaef3d3f524cfac0dacd878", size = 5018099 }, + { url = "https://files.pythonhosted.org/packages/a6/04/cec160f9f4b862788e2a0167616472a5695b2f569bd62204938ab674835d/couchbase-4.3.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:374ce392558f1688ac073aa0b15c256b1a441201d965811fd862357ff05d27a9", size = 5672633 }, + { url = "https://files.pythonhosted.org/packages/1b/a2/1da2ab45412b9414e2c6a578e0e7a24f29b9261ef7de11707c2fc98045b8/couchbase-4.3.6-cp312-cp312-win_amd64.whl", hash = "sha256:cd734333de34d8594504c163bb6c47aea9cc1f2cefdf8e91875dd9bf14e61e29", size = 4013298 }, ] [[package]] @@ -1112,43 +1105,36 @@ sdist = { url = "https://files.pythonhosted.org/packages/6b/b0/e595ce2a2527e169c [[package]] name = "cryptography" -version = "44.0.3" +version = "42.0.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/d6/1411ab4d6108ab167d06254c5be517681f1e331f90edf1379895bcb87020/cryptography-44.0.3.tar.gz", hash = "sha256:fe19d8bc5536a91a24a8133328880a41831b6c5df54599a8417b62fe015d3053", size = 711096 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/53/c776d80e9d26441bb3868457909b4e74dd9ccabd182e10b2b0ae7a07e265/cryptography-44.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:962bc30480a08d133e631e8dfd4783ab71cc9e33d5d7c1e192f0b7c06397bb88", size = 6670281 }, - { url = "https://files.pythonhosted.org/packages/6a/06/af2cf8d56ef87c77319e9086601bef621bedf40f6f59069e1b6d1ec498c5/cryptography-44.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc61e8f3bf5b60346d89cd3d37231019c17a081208dfbbd6e1605ba03fa137", size = 3959305 }, - { url = "https://files.pythonhosted.org/packages/ae/01/80de3bec64627207d030f47bf3536889efee8913cd363e78ca9a09b13c8e/cryptography-44.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58968d331425a6f9eedcee087f77fd3c927c88f55368f43ff7e0a19891f2642c", size = 4171040 }, - { url = "https://files.pythonhosted.org/packages/bd/48/bb16b7541d207a19d9ae8b541c70037a05e473ddc72ccb1386524d4f023c/cryptography-44.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e28d62e59a4dbd1d22e747f57d4f00c459af22181f0b2f787ea83f5a876d7c76", size = 3963411 }, - { url = "https://files.pythonhosted.org/packages/42/b2/7d31f2af5591d217d71d37d044ef5412945a8a8e98d5a2a8ae4fd9cd4489/cryptography-44.0.3-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af653022a0c25ef2e3ffb2c673a50e5a0d02fecc41608f4954176f1933b12359", size = 3689263 }, - { url = "https://files.pythonhosted.org/packages/25/50/c0dfb9d87ae88ccc01aad8eb93e23cfbcea6a6a106a9b63a7b14c1f93c75/cryptography-44.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:157f1f3b8d941c2bd8f3ffee0af9b049c9665c39d3da9db2dc338feca5e98a43", size = 4196198 }, - { url = "https://files.pythonhosted.org/packages/66/c9/55c6b8794a74da652690c898cb43906310a3e4e4f6ee0b5f8b3b3e70c441/cryptography-44.0.3-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:c6cd67722619e4d55fdb42ead64ed8843d64638e9c07f4011163e46bc512cf01", size = 3966502 }, - { url = "https://files.pythonhosted.org/packages/b6/f7/7cb5488c682ca59a02a32ec5f975074084db4c983f849d47b7b67cc8697a/cryptography-44.0.3-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b424563394c369a804ecbee9b06dfb34997f19d00b3518e39f83a5642618397d", size = 4196173 }, - { url = "https://files.pythonhosted.org/packages/d2/0b/2f789a8403ae089b0b121f8f54f4a3e5228df756e2146efdf4a09a3d5083/cryptography-44.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c91fc8e8fd78af553f98bc7f2a1d8db977334e4eea302a4bfd75b9461c2d8904", size = 4087713 }, - { url = "https://files.pythonhosted.org/packages/1d/aa/330c13655f1af398fc154089295cf259252f0ba5df93b4bc9d9c7d7f843e/cryptography-44.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25cd194c39fa5a0aa4169125ee27d1172097857b27109a45fadc59653ec06f44", size = 4299064 }, - { url = "https://files.pythonhosted.org/packages/10/a8/8c540a421b44fd267a7d58a1fd5f072a552d72204a3f08194f98889de76d/cryptography-44.0.3-cp37-abi3-win32.whl", hash = "sha256:3be3f649d91cb182c3a6bd336de8b61a0a71965bd13d1a04a0e15b39c3d5809d", size = 2773887 }, - { url = "https://files.pythonhosted.org/packages/b9/0d/c4b1657c39ead18d76bbd122da86bd95bdc4095413460d09544000a17d56/cryptography-44.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:3883076d5c4cc56dbef0b898a74eb6992fdac29a7b9013870b34efe4ddb39a0d", size = 3209737 }, - { url = "https://files.pythonhosted.org/packages/34/a3/ad08e0bcc34ad436013458d7528e83ac29910943cea42ad7dd4141a27bbb/cryptography-44.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:5639c2b16764c6f76eedf722dbad9a0914960d3489c0cc38694ddf9464f1bb2f", size = 6673501 }, - { url = "https://files.pythonhosted.org/packages/b1/f0/7491d44bba8d28b464a5bc8cc709f25a51e3eac54c0a4444cf2473a57c37/cryptography-44.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ffef566ac88f75967d7abd852ed5f182da252d23fac11b4766da3957766759", size = 3960307 }, - { url = "https://files.pythonhosted.org/packages/f7/c8/e5c5d0e1364d3346a5747cdcd7ecbb23ca87e6dea4f942a44e88be349f06/cryptography-44.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:192ed30fac1728f7587c6f4613c29c584abdc565d7417c13904708db10206645", size = 4170876 }, - { url = "https://files.pythonhosted.org/packages/73/96/025cb26fc351d8c7d3a1c44e20cf9a01e9f7cf740353c9c7a17072e4b264/cryptography-44.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7d5fe7195c27c32a64955740b949070f21cba664604291c298518d2e255931d2", size = 3964127 }, - { url = "https://files.pythonhosted.org/packages/01/44/eb6522db7d9f84e8833ba3bf63313f8e257729cf3a8917379473fcfd6601/cryptography-44.0.3-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3f07943aa4d7dad689e3bb1638ddc4944cc5e0921e3c227486daae0e31a05e54", size = 3689164 }, - { url = "https://files.pythonhosted.org/packages/68/fb/d61a4defd0d6cee20b1b8a1ea8f5e25007e26aeb413ca53835f0cae2bcd1/cryptography-44.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb90f60e03d563ca2445099edf605c16ed1d5b15182d21831f58460c48bffb93", size = 4198081 }, - { url = "https://files.pythonhosted.org/packages/1b/50/457f6911d36432a8811c3ab8bd5a6090e8d18ce655c22820994913dd06ea/cryptography-44.0.3-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ab0b005721cc0039e885ac3503825661bd9810b15d4f374e473f8c89b7d5460c", size = 3967716 }, - { url = "https://files.pythonhosted.org/packages/35/6e/dca39d553075980ccb631955c47b93d87d27f3596da8d48b1ae81463d915/cryptography-44.0.3-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:3bb0847e6363c037df8f6ede57d88eaf3410ca2267fb12275370a76f85786a6f", size = 4197398 }, - { url = "https://files.pythonhosted.org/packages/9b/9d/d1f2fe681eabc682067c66a74addd46c887ebacf39038ba01f8860338d3d/cryptography-44.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0cc66c74c797e1db750aaa842ad5b8b78e14805a9b5d1348dc603612d3e3ff5", size = 4087900 }, - { url = "https://files.pythonhosted.org/packages/c4/f5/3599e48c5464580b73b236aafb20973b953cd2e7b44c7c2533de1d888446/cryptography-44.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6866df152b581f9429020320e5eb9794c8780e90f7ccb021940d7f50ee00ae0b", size = 4301067 }, - { url = "https://files.pythonhosted.org/packages/a7/6c/d2c48c8137eb39d0c193274db5c04a75dab20d2f7c3f81a7dcc3a8897701/cryptography-44.0.3-cp39-abi3-win32.whl", hash = "sha256:c138abae3a12a94c75c10499f1cbae81294a6f983b3af066390adee73f433028", size = 2775467 }, - { url = "https://files.pythonhosted.org/packages/c9/ad/51f212198681ea7b0deaaf8846ee10af99fba4e894f67b353524eab2bbe5/cryptography-44.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:5d186f32e52e66994dce4f766884bcb9c68b8da62d61d9d215bfe5fb56d21334", size = 3210375 }, - { url = "https://files.pythonhosted.org/packages/8d/4b/c11ad0b6c061902de5223892d680e89c06c7c4d606305eb8de56c5427ae6/cryptography-44.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:896530bc9107b226f265effa7ef3f21270f18a2026bc09fed1ebd7b66ddf6375", size = 3390230 }, - { url = "https://files.pythonhosted.org/packages/58/11/0a6bf45d53b9b2290ea3cec30e78b78e6ca29dc101e2e296872a0ffe1335/cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9b4d4a5dbee05a2c390bf212e78b99434efec37b17a4bff42f50285c5c8c9647", size = 3895216 }, - { url = "https://files.pythonhosted.org/packages/0a/27/b28cdeb7270e957f0077a2c2bfad1b38f72f1f6d699679f97b816ca33642/cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02f55fb4f8b79c1221b0961488eaae21015b69b210e18c386b69de182ebb1259", size = 4115044 }, - { url = "https://files.pythonhosted.org/packages/35/b0/ec4082d3793f03cb248881fecefc26015813199b88f33e3e990a43f79835/cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dd3db61b8fe5be220eee484a17233287d0be6932d056cf5738225b9c05ef4fff", size = 3898034 }, - { url = "https://files.pythonhosted.org/packages/0b/7f/adf62e0b8e8d04d50c9a91282a57628c00c54d4ae75e2b02a223bd1f2613/cryptography-44.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:978631ec51a6bbc0b7e58f23b68a8ce9e5f09721940933e9c217068388789fe5", size = 4114449 }, - { url = "https://files.pythonhosted.org/packages/87/62/d69eb4a8ee231f4bf733a92caf9da13f1c81a44e874b1d4080c25ecbb723/cryptography-44.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:5d20cc348cca3a8aa7312f42ab953a56e15323800ca3ab0706b8cd452a3a056c", size = 3134369 }, +sdist = { url = "https://files.pythonhosted.org/packages/93/a7/1498799a2ea06148463a9a2c10ab2f6a921a74fb19e231b27dc412a748e2/cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", size = 671250 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/8b/1b929ba8139430e09e140e6939c2b29c18df1f2fc2149e41bdbdcdaf5d1f/cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", size = 5899961 }, + { url = "https://files.pythonhosted.org/packages/fa/5d/31d833daa800e4fab33209843095df7adb4a78ea536929145534cbc15026/cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", size = 3114353 }, + { url = "https://files.pythonhosted.org/packages/5d/32/f6326c70a9f0f258a201d3b2632bca586ea24d214cec3cf36e374040e273/cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", size = 3647773 }, + { url = "https://files.pythonhosted.org/packages/35/66/2d87e9ca95c82c7ee5f2c09716fc4c4242c1ae6647b9bd27e55e920e9f10/cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", size = 3839763 }, + { url = "https://files.pythonhosted.org/packages/c2/de/8083fa2e68d403553a01a9323f4f8b9d7ffed09928ba25635c29fb28c1e7/cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", size = 3632661 }, + { url = "https://files.pythonhosted.org/packages/07/40/d6f6819c62e808ea74639c3c640f7edd636b86cce62cb14943996a15df92/cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", size = 3851536 }, + { url = "https://files.pythonhosted.org/packages/5c/46/de71d48abf2b6d3c808f4fbb0f4dc44a4e72786be23df0541aa2a3f6fd7e/cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", size = 3754209 }, + { url = "https://files.pythonhosted.org/packages/25/c9/86f04e150c5d5d5e4a731a2c1e0e43da84d901f388e3fea3d5de98d689a7/cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", size = 3923551 }, + { url = "https://files.pythonhosted.org/packages/53/c2/903014dafb7271fb148887d4355b2e90319cad6e810663be622b0c933fc9/cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", size = 3739265 }, + { url = "https://files.pythonhosted.org/packages/95/26/82d704d988a193cbdc69ac3b41c687c36eaed1642cce52530ad810c35645/cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", size = 3937371 }, + { url = "https://files.pythonhosted.org/packages/cf/71/4e0d05c9acd638a225f57fb6162aa3d03613c11b76893c23ea4675bb28c5/cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", size = 2438849 }, + { url = "https://files.pythonhosted.org/packages/06/0f/78da3cad74f2ba6c45321dc90394d70420ea846730dc042ef527f5a224b5/cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", size = 2889090 }, + { url = "https://files.pythonhosted.org/packages/60/12/f064af29190cdb1d38fe07f3db6126091639e1dece7ec77c4ff037d49193/cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", size = 5901232 }, + { url = "https://files.pythonhosted.org/packages/43/c2/4a3eef67e009a522711ebd8ac89424c3a7fe591ece7035d964419ad52a1d/cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", size = 3648711 }, + { url = "https://files.pythonhosted.org/packages/49/1c/9f6d13cc8041c05eebff1154e4e71bedd1db8e174fff999054435994187a/cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", size = 3841968 }, + { url = "https://files.pythonhosted.org/packages/5f/f9/c3d4f19b82bdb25a3d857fe96e7e571c981810e47e3f299cc13ac429066a/cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", size = 3633032 }, + { url = "https://files.pythonhosted.org/packages/fa/e2/b7e6e8c261536c489d9cf908769880d94bd5d9a187e166b0dc838d2e6a56/cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", size = 3852478 }, + { url = "https://files.pythonhosted.org/packages/a2/68/e16751f6b859bc120f53fddbf3ebada5c34f0e9689d8af32884d8b2e4b4c/cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e", size = 3754102 }, + { url = "https://files.pythonhosted.org/packages/0f/38/85c74d0ac4c540780e072b1e6f148ecb718418c1062edcb20d22f3ec5bbb/cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", size = 3925042 }, + { url = "https://files.pythonhosted.org/packages/89/f4/a8b982e88eb5350407ebdbf4717b55043271d878705329e107f4783555f2/cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", size = 3738833 }, + { url = "https://files.pythonhosted.org/packages/fd/2b/be327b580645927bb1a1f32d5a175b897a9b956bc085b095e15c40bac9ed/cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", size = 3938751 }, + { url = "https://files.pythonhosted.org/packages/3c/d5/c6a78ffccdbe4516711ebaa9ed2c7eb6ac5dfa3dc920f2c7e920af2418b0/cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", size = 2439281 }, + { url = "https://files.pythonhosted.org/packages/a2/7b/b0d330852dd5953daee6b15f742f15d9f18e9c0154eb4cfcc8718f0436da/cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", size = 2886038 }, ] [[package]] @@ -1242,7 +1228,6 @@ dependencies = [ { name = "mailchimp-transactional" }, { name = "markdown" }, { name = "numpy" }, - { name = "oci" }, { name = "openai" }, { name = "openpyxl" }, { name = "opentelemetry-api" }, @@ -1306,6 +1291,7 @@ dev = [ { name = "types-aiofiles" }, { name = "types-beautifulsoup4" }, { name = "types-cachetools" }, + { name = "types-cffi" }, { name = "types-colorama" }, { name = "types-defusedxml" }, { name = "types-deprecated" }, @@ -1328,12 +1314,14 @@ dev = [ { name = "types-psycopg2" }, { name = "types-pygments" }, { name = "types-pymysql" }, + { name = "types-pyopenssl" }, { name = "types-python-dateutil" }, { name = "types-pywin32" }, { name = "types-pyyaml" }, { name = "types-regex" }, { name = "types-requests" }, { name = "types-requests-oauthlib" }, + { name = "types-setuptools" }, { name = "types-shapely" }, { name = "types-simplejson" }, { name = "types-six" }, @@ -1392,7 +1380,7 @@ requires-dist = [ { name = "chardet", specifier = "~=5.1.0" }, { name = "flask", specifier = "~=3.1.0" }, { name = "flask-compress", specifier = "~=1.17" }, - { name = "flask-cors", specifier = "~=5.0.0" }, + { name = "flask-cors", specifier = "~=6.0.0" }, { name = "flask-login", specifier = "~=0.6.3" }, { name = "flask-migrate", specifier = "~=4.0.7" }, { name = "flask-restful", specifier = "~=0.3.10" }, @@ -1414,7 +1402,6 @@ requires-dist = [ { name = "mailchimp-transactional", specifier = "~=1.0.50" }, { name = "markdown", specifier = "~=3.5.1" }, { name = "numpy", specifier = "~=1.26.4" }, - { name = "oci", specifier = "~=2.135.1" }, { name = "openai", specifier = "~=1.61.0" }, { name = "openpyxl", specifier = "~=3.1.5" }, { name = "opentelemetry-api", specifier = "==1.27.0" }, @@ -1478,6 +1465,7 @@ dev = [ { name = "types-aiofiles", specifier = "~=24.1.0" }, { name = "types-beautifulsoup4", specifier = "~=4.12.0" }, { name = "types-cachetools", specifier = "~=5.5.0" }, + { name = "types-cffi", specifier = ">=1.17.0" }, { name = "types-colorama", specifier = "~=0.4.15" }, { name = "types-defusedxml", specifier = "~=0.7.0" }, { name = "types-deprecated", specifier = "~=1.2.15" }, @@ -1500,18 +1488,20 @@ dev = [ { name = "types-psycopg2", specifier = "~=2.9.21" }, { name = "types-pygments", specifier = "~=2.19.0" }, { name = "types-pymysql", specifier = "~=1.1.0" }, + { name = "types-pyopenssl", specifier = ">=24.1.0" }, { name = "types-python-dateutil", specifier = "~=2.9.0" }, { name = "types-pywin32", specifier = "~=310.0.0" }, { name = "types-pyyaml", specifier = "~=6.0.12" }, { name = "types-regex", specifier = "~=2024.11.6" }, { name = "types-requests", specifier = "~=2.32.0" }, { name = "types-requests-oauthlib", specifier = "~=2.0.0" }, + { name = "types-setuptools", specifier = ">=80.9.0" }, { name = "types-shapely", specifier = "~=2.0.0" }, - { name = "types-simplejson", specifier = "~=3.20.0" }, - { name = "types-six", specifier = "~=1.17.0" }, - { name = "types-tensorflow", specifier = "~=2.18.0" }, - { name = "types-tqdm", specifier = "~=4.67.0" }, - { name = "types-ujson", specifier = "~=5.10.0" }, + { name = "types-simplejson", specifier = ">=3.20.0" }, + { name = "types-six", specifier = ">=1.17.0" }, + { name = "types-tensorflow", specifier = ">=2.18.0" }, + { name = "types-tqdm", specifier = ">=4.67.0" }, + { name = "types-ujson", specifier = ">=5.10.0" }, ] storage = [ { name = "azure-storage-blob", specifier = "==12.13.0" }, @@ -1609,11 +1599,11 @@ wheels = [ [[package]] name = "durationpy" -version = "0.9" +version = "0.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/e9/f49c4e7fccb77fa5c43c2480e09a857a78b41e7331a75e128ed5df45c56b/durationpy-0.9.tar.gz", hash = "sha256:fd3feb0a69a0057d582ef643c355c40d2fa1c942191f914d12203b1a01ac722a", size = 3186 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/a4/e44218c2b394e31a6dd0d6b095c4e1f32d0be54c2a4b250032d717647bab/durationpy-0.10.tar.gz", hash = "sha256:1fa6893409a6e739c9c72334fc65cca1f355dbdd93405d30f726deb5bde42fba", size = 3335 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/a3/ac312faeceffd2d8f86bc6dcb5c401188ba5a01bc88e69bed97578a0dfcd/durationpy-0.9-py3-none-any.whl", hash = "sha256:e65359a7af5cedad07fb77a2dd3f390f8eb0b74cb845589fa6c057086834dd38", size = 3461 }, + { url = "https://files.pythonhosted.org/packages/b0/0d/9feae160378a3553fa9a339b0e9c1a048e147a4127210e286ef18b730f03/durationpy-0.10-py3-none-any.whl", hash = "sha256:3b41e1b601234296b4fb368338fdcd3e13e0b4fb5b67345948f4f2bf9868b286", size = 3922 }, ] [[package]] @@ -1677,15 +1667,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059 }, ] -[[package]] -name = "eval-type-backport" -version = "0.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/ea/8b0ac4469d4c347c6a385ff09dc3c048c2d021696664e26c7ee6791631b5/eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1", size = 9079 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a", size = 5830 }, -] - [[package]] name = "faker" version = "32.1.0" @@ -1733,18 +1714,19 @@ wheels = [ [[package]] name = "flask" -version = "3.1.0" +version = "3.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "blinker" }, { name = "click" }, { name = "itsdangerous" }, { name = "jinja2" }, + { name = "markupsafe" }, { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/89/50/dff6380f1c7f84135484e176e0cac8690af72fa90e932ad2a0a60e28c69b/flask-3.1.0.tar.gz", hash = "sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac", size = 680824 } +sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/47/93213ee66ef8fae3b93b3e29206f6b251e65c97bd91d8e1c5596ef15af0a/flask-3.1.0-py3-none-any.whl", hash = "sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136", size = 102979 }, + { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305 }, ] [[package]] @@ -1765,15 +1747,15 @@ wheels = [ [[package]] name = "flask-cors" -version = "5.0.1" +version = "6.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "flask" }, { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/32/d8/667bd90d1ee41c96e938bafe81052494e70b7abd9498c4a0215c103b9667/flask_cors-5.0.1.tar.gz", hash = "sha256:6ccb38d16d6b72bbc156c1c3f192bc435bfcc3c2bc864b2df1eb9b2d97b2403c", size = 11643 } +sdist = { url = "https://files.pythonhosted.org/packages/20/e7/b3c6afdd984672b55dff07482699c688af6c01bd7fd5dd55f9c9d1a88d1c/flask_cors-6.0.0.tar.gz", hash = "sha256:4592c1570246bf7beee96b74bc0adbbfcb1b0318f6ba05c412e8909eceec3393", size = 11875 } wheels = [ - { url = "https://files.pythonhosted.org/packages/85/61/4aea5fb55be1b6f95e604627dc6c50c47d693e39cab2ac086ee0155a0abd/flask_cors-5.0.1-py3-none-any.whl", hash = "sha256:fa5cb364ead54bbf401a26dbf03030c6b18fb2fcaf70408096a572b409586b0c", size = 11296 }, + { url = "https://files.pythonhosted.org/packages/ba/f0/0ee29090016345938f016ee98aa8b5de1c500ee93491dc0c76495848fca1/flask_cors-6.0.0-py3-none-any.whl", hash = "sha256:6332073356452343a8ccddbfec7befdc3fdd040141fe776ec9b94c262f058657", size = 11549 }, ] [[package]] @@ -1885,11 +1867,11 @@ wheels = [ [[package]] name = "fsspec" -version = "2025.3.2" +version = "2025.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/d8/8425e6ba5fcec61a1d16e41b1b71d2bf9344f1fe48012c2b48b9620feae5/fsspec-2025.3.2.tar.gz", hash = "sha256:e52c77ef398680bbd6a98c0e628fbc469491282981209907bbc8aea76a04fdc6", size = 299281 } +sdist = { url = "https://files.pythonhosted.org/packages/00/f7/27f15d41f0ed38e8fcc488584b57e902b331da7f7c6dcda53721b15838fc/fsspec-2025.5.1.tar.gz", hash = "sha256:2e55e47a540b91843b755e83ded97c6e897fa0942b11490113f09e9c443c2475", size = 303033 } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/4b/e0cfc1a6f17e990f3e64b7d941ddc4acdc7b19d6edd51abf495f32b1a9e4/fsspec-2025.3.2-py3-none-any.whl", hash = "sha256:2daf8dc3d1dfa65b6aa37748d112773a7a08416f6c70d96b264c96476ecaf711", size = 194435 }, + { url = "https://files.pythonhosted.org/packages/bb/61/78c7b3851add1481b048b5fdc29067397a1784e2910592bc81bb3f608635/fsspec-2025.5.1-py3-none-any.whl", hash = "sha256:24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462", size = 199052 }, ] [[package]] @@ -2078,7 +2060,7 @@ wheels = [ [[package]] name = "google-cloud-bigquery" -version = "3.32.0" +version = "3.34.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core", extra = ["grpc"] }, @@ -2089,9 +2071,9 @@ dependencies = [ { name = "python-dateutil" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/cf/174ea37f0410f0702c3582c09bae45d6f43c6eabe2858ab5fb2a4319e15f/google_cloud_bigquery-3.32.0.tar.gz", hash = "sha256:f1c53d73a6d255c8cd0ca7a0c077d95224217427a4b7dcf9913ea0298a2961e8", size = 487055 } +sdist = { url = "https://files.pythonhosted.org/packages/24/f9/e9da2d56d7028f05c0e2f5edf6ce43c773220c3172666c3dd925791d763d/google_cloud_bigquery-3.34.0.tar.gz", hash = "sha256:5ee1a78ba5c2ccb9f9a8b2bf3ed76b378ea68f49b6cac0544dc55cc97ff7c1ce", size = 489091 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/c3/f3f6179f54e4b4ac2c6abaa8186054fd1d7d881676bb3caef9688e5fac3d/google_cloud_bigquery-3.32.0-py3-none-any.whl", hash = "sha256:ff38d21d70c4563d2473db288d2a9fe44f071d928bbad6d029ac9ba0b8a36b7a", size = 253121 }, + { url = "https://files.pythonhosted.org/packages/b1/7e/7115c4f67ca0bc678f25bff1eab56cc37d06eb9a3978940b2ebd0705aa0a/google_cloud_bigquery-3.34.0-py3-none-any.whl", hash = "sha256:de20ded0680f8136d92ff5256270b5920dfe4fae479f5d0f73e90e5df30b1cf7", size = 253555 }, ] [[package]] @@ -2204,7 +2186,7 @@ wheels = [ [[package]] name = "gql" -version = "3.5.2" +version = "3.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -2212,9 +2194,9 @@ dependencies = [ { name = "graphql-core" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/ef/5298d9d628b6a54b3b810052cb5a935d324fe28d9bfdeb741733d5c2446b/gql-3.5.2.tar.gz", hash = "sha256:07e1325b820c8ba9478e95de27ce9f23250486e7e79113dbb7659a442dc13e74", size = 180502 } +sdist = { url = "https://files.pythonhosted.org/packages/34/ed/44ffd30b06b3afc8274ee2f38c3c1b61fe4740bf03d92083e43d2c17ac77/gql-3.5.3.tar.gz", hash = "sha256:393b8c049d58e0d2f5461b9d738a2b5f904186a40395500b4a84dd092d56e42b", size = 180504 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/71/b028b937992056e721bbf0371e13819fcca0dacde7b3c821f775ed903917/gql-3.5.2-py2.py3-none-any.whl", hash = "sha256:c830ffc38b3997b2a146317b27758305ab3d0da3bde607b49f34e32affb23ba2", size = 74346 }, + { url = "https://files.pythonhosted.org/packages/cb/50/2f4e99b216821ac921dbebf91c644ba95818f5d07857acadee17220221f3/gql-3.5.3-py2.py3-none-any.whl", hash = "sha256:e1fcbde2893fcafdd28114ece87ff47f1cc339a31db271fc4e1d528f5a1d4fbc", size = 74348 }, ] [package.optional-dependencies] @@ -2228,11 +2210,11 @@ requests = [ [[package]] name = "graphql-core" -version = "3.2.4" +version = "3.2.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/9e/aa527fb09a9d7399d5d7d2aa2da490e4580707652d3b4fc156996ae88a5b/graphql-core-3.2.4.tar.gz", hash = "sha256:acbe2e800980d0e39b4685dd058c2f4042660b89ebca38af83020fd872ff1264", size = 504611 } +sdist = { url = "https://files.pythonhosted.org/packages/c4/16/7574029da84834349b60ed71614d66ca3afe46e9bf9c7b9562102acb7d4f/graphql_core-3.2.6.tar.gz", hash = "sha256:c08eec22f9e40f0bd61d805907e3b3b1b9a320bc606e23dc145eebca07c8fbab", size = 505353 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/33/cc72c4c658c6316f188a60bc4e5a91cd4ceaaa8c3e7e691ac9297e4e72c7/graphql_core-3.2.4-py3-none-any.whl", hash = "sha256:1604f2042edc5f3114f49cac9d77e25863be51b23a54a61a23245cf32f6476f0", size = 203179 }, + { url = "https://files.pythonhosted.org/packages/ae/4f/7297663840621022bc73c22d7d9d80dbc78b4db6297f764b545cd5dd462d/graphql_core-3.2.6-py3-none-any.whl", hash = "sha256:78b016718c161a6fb20a7d97bbf107f331cd1afe53e45566c59f776ed7f0b45f", size = 203416 }, ] [[package]] @@ -2380,55 +2362,55 @@ wheels = [ [[package]] name = "hf-xet" -version = "1.1.1" +version = "1.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/09/e2fc5ccd6f9828efbd9135d5aab70895fa6891752ce84c57026c48f3f33d/hf_xet-1.1.1.tar.gz", hash = "sha256:3e75d6e04c38c80115b640c025d68c3dc14d62f8b244011dfe547363674a1e87", size = 277864 } +sdist = { url = "https://files.pythonhosted.org/packages/95/be/58f20728a5b445f8b064e74f0618897b3439f5ef90934da1916b9dfac76f/hf_xet-1.1.2.tar.gz", hash = "sha256:3712d6d4819d3976a1c18e36db9f503e296283f9363af818f50703506ed63da3", size = 467009 } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/f5/81194ea8e4a585d7d4d0f2ad1ca16e05a4b0c5a385bb2610a8e6da1d2c3d/hf_xet-1.1.1-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e39a8513f0854656116c837d387d9a41e9d78430b1a181442f04c223cbc4e8f8", size = 5274857 }, - { url = "https://files.pythonhosted.org/packages/55/3c/36342b3fa247f2580821a4b183d38f36fb20e911a8307df625790e734359/hf_xet-1.1.1-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:c60cd67be384cb9e592fa6dfd29a10fddffa1feb2f3b31f53e980630d1ca0fd6", size = 5079657 }, - { url = "https://files.pythonhosted.org/packages/b0/c1/4f770cc7be79287905e13765d4a7e1949dce3483f90867f532ff56e7126b/hf_xet-1.1.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5efc6cf15930d9b0cef25c0444e00c2f55d9e09f856f26ed8c809fd5cd1aa044", size = 25506200 }, - { url = "https://files.pythonhosted.org/packages/94/69/1ec612f8e9e2ca27563adfca926cfb41bbe988e30d4cd6fc1e0c019e5570/hf_xet-1.1.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:504bbc8341edc2aa4b3c20c1fdda818554ab34e4175730f42e2a90436cbbe706", size = 24469080 }, - { url = "https://files.pythonhosted.org/packages/8d/96/9201773a0ebb982aa5936f19bdd04d404bc5d74e23f30bce6e857757998b/hf_xet-1.1.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87d030157a21016c2cddf757a5fd6f1f364d86afef6e190e63a37dd4dc6f6c98", size = 25641374 }, - { url = "https://files.pythonhosted.org/packages/ba/14/10a4cf526070e774bdc7ce68202dc27a15751ddc22c6b47a5ecb6d8ea4ad/hf_xet-1.1.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6e9b640f0f002b3bea36739b30cf3133b3175c27a342b39315be9a9bdb0cec5b", size = 25425434 }, - { url = "https://files.pythonhosted.org/packages/bd/25/7015a82b3b165747ba85b0383e5d5278d268f3a30460f6d55849903cf272/hf_xet-1.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:215a4e95009a0b9795ca3cf33db4e8d1248139593d7e1185661cd19b062d2b82", size = 4391897 }, + { url = "https://files.pythonhosted.org/packages/45/ae/f1a63f75d9886f18a80220ba31a1c7b9c4752f03aae452f358f538c6a991/hf_xet-1.1.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dfd1873fd648488c70735cb60f7728512bca0e459e61fcd107069143cd798469", size = 2642559 }, + { url = "https://files.pythonhosted.org/packages/50/ab/d2c83ae18f1015d926defd5bfbe94c62d15e93f900e6a192e318ee947105/hf_xet-1.1.2-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:29b584983b2d977c44157d9241dcf0fd50acde0b7bff8897fe4386912330090d", size = 2541360 }, + { url = "https://files.pythonhosted.org/packages/9f/a7/693dc9f34f979e30a378125e2150a0b2d8d166e6d83ce3950eeb81e560aa/hf_xet-1.1.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b29ac84298147fe9164cc55ad994ba47399f90b5d045b0b803b99cf5f06d8ec", size = 5183081 }, + { url = "https://files.pythonhosted.org/packages/3d/23/c48607883f692a36c0a7735f47f98bad32dbe459a32d1568c0f21576985d/hf_xet-1.1.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d921ba32615676e436a0d15e162331abc9ed43d440916b1d836dc27ce1546173", size = 5356100 }, + { url = "https://files.pythonhosted.org/packages/eb/5b/b2316c7f1076da0582b52ea228f68bea95e243c388440d1dc80297c9d813/hf_xet-1.1.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:d9b03c34e13c44893ab6e8fea18ee8d2a6878c15328dd3aabedbdd83ee9f2ed3", size = 5647688 }, + { url = "https://files.pythonhosted.org/packages/2c/98/e6995f0fa579929da7795c961f403f4ee84af36c625963f52741d56f242c/hf_xet-1.1.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:01b18608955b3d826307d37da8bd38b28a46cd2d9908b3a3655d1363274f941a", size = 5322627 }, + { url = "https://files.pythonhosted.org/packages/59/40/8f1d5a44a64d8bf9e3c19576e789f716af54875b46daae65426714e75db1/hf_xet-1.1.2-cp37-abi3-win_amd64.whl", hash = "sha256:3562902c81299b09f3582ddfb324400c6a901a2f3bc854f83556495755f4954c", size = 2739542 }, ] [[package]] name = "hiredis" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/6f/a1b4749fa7d980f4d11e7f6da42658520fb9a92538844b2012427ad9aa06/hiredis-3.1.1.tar.gz", hash = "sha256:63f22cd7b441cbe13d24087b338e4e6a8f454f333cf35a6ed27ef13a60ca8b0b", size = 87898 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/89/ed8072ca29a52a01a6cf9c8d68141effc35a3a1d511dd6705f15a585fea0/hiredis-3.1.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:80d98b1d21002c7045ef4c7bae9a41a7a5f6585d08c345850c32ec08d05bd8fe", size = 81254 }, - { url = "https://files.pythonhosted.org/packages/64/90/65251dbbf742c6c8e19735f232d09e1f13fbd033e19d1397e1d46e8ac187/hiredis-3.1.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:9d943c754273fda5908b6c6f4c64c9dcdc4718bb96fa5c699e7fee687d713566", size = 44605 }, - { url = "https://files.pythonhosted.org/packages/75/bd/28ecc23080e5b74d7bba977829bcd27eec3207809ee6b359594a4d33ab84/hiredis-3.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e0b02238141b685de2e8fcf361d79359a77ca9b440e566280e9dda875de03d1", size = 42535 }, - { url = "https://files.pythonhosted.org/packages/bf/da/bed1270992cd1d1647de9e9cd4ee3902f4c21453de57ab5837e6183ca37f/hiredis-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e2737844ca1c2477808f2612093c9fad68b42dd17fba1b348c95232cf895d84", size = 167838 }, - { url = "https://files.pythonhosted.org/packages/3a/16/28ee85a8a5835259ae427eaf6427a00338651a695074e8a4af657165dc98/hiredis-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf6c2ea105477a7ea837381255f884b60775a8f6b527d16416d0e2fc4dd107d6", size = 178703 }, - { url = "https://files.pythonhosted.org/packages/e5/06/49292341ec3da3ffcd49a23a8fbca4f7a931c37ed00e1521136efcb3dd57/hiredis-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32acf786b0e7117b1d8ffc8e5a1cfab57c73798658ed02228b5e9fa71fd4eaff", size = 168133 }, - { url = "https://files.pythonhosted.org/packages/d7/ce/038d537b8c41caef11a9ee6815e4f1fcf59aab1f222ee48330eaa15d2b85/hiredis-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98aeff9c038fd456e2e1a789abab775a1fcd1fd993170b1602f224e8fb8bc507", size = 168250 }, - { url = "https://files.pythonhosted.org/packages/21/76/3a3da9911a9c98600c72095093629d4646cbcdb4ffc1f2519170a476c801/hiredis-3.1.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb89a866e61c81ed2da3dc7eaee2b3e70d444aa350aa893321d637e77cda1790", size = 164082 }, - { url = "https://files.pythonhosted.org/packages/ea/66/6043f47f5703152339b11d285ff621eb73d383861289df749d1b84563f0a/hiredis-3.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec1e10e02eaa8df9f43d6e4b3d201cfcc33d08d263f3f1ad59e8433bca4c25e8", size = 162011 }, - { url = "https://files.pythonhosted.org/packages/1d/2d/84ffc08d64b1f5fb09502fe5b8e6557b864c669e330ab65e7f2dded1e741/hiredis-3.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c32869095b412d401ad8358dbb4d8c50661a301237e55fa865c4de83d1a2b5f2", size = 161035 }, - { url = "https://files.pythonhosted.org/packages/06/ff/636262e75da46b1e07ef0e5b27774572245bd20df97d3b409836ea40a3c4/hiredis-3.1.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ef96546415a0ec22534ee5ce30ca5e0fefc1c1b9f69ded167748fa6b2da55a73", size = 172939 }, - { url = "https://files.pythonhosted.org/packages/83/82/f157db3b867dff34d586948adfc48279ccc8011c2b2b49fb9a685c80da4e/hiredis-3.1.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7bfbc714b3c48f62064e1ff031495c977d7554d9ff3d799bb3f8c40256af94bb", size = 165234 }, - { url = "https://files.pythonhosted.org/packages/6a/5f/3ed30df0b6ac34b48ecbce8a7c633a05720b8d3b446d3ec518a947f8f60b/hiredis-3.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9bd0e4b5a0bd8c5c7137b2fb96eac1a36fca65ab822bfd7e7a712c5f7faf956", size = 163132 }, - { url = "https://files.pythonhosted.org/packages/c1/71/d2e5ed355140178f61a84a102a6b4b30e80da355d86172fa1e14aa11d599/hiredis-3.1.1-cp311-cp311-win32.whl", hash = "sha256:de94a0fbdbf1436a94443be8ddf9357d3f6637a1a072a22442135eca634157cc", size = 20060 }, - { url = "https://files.pythonhosted.org/packages/fe/9a/8ad1c43268fde062e717f5f16e7948c6fc31ae885a90061de79e77d01296/hiredis-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:b60488f5ec1d9903b3b0ce744b76c570e82cb1b53d3045df74111a5d5bd2c134", size = 21721 }, - { url = "https://files.pythonhosted.org/packages/22/22/b59206aa280f7cd8b6838393765da19648258c0f7d0a65513ea9ca83d373/hiredis-3.1.1-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:b7c3e47b3eec883add6ff6d8dbcc314e7bacd73c5146e4587aa3610a1d59c1b0", size = 81402 }, - { url = "https://files.pythonhosted.org/packages/4a/d2/9c889337dbd812a27725c84773db187f014482708aa21d1f4aac17afe805/hiredis-3.1.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:dba871b974ebd60258cf723a096a4170cc1241d9a32273513fc9da37410ff4a1", size = 44709 }, - { url = "https://files.pythonhosted.org/packages/de/e3/66e4345a39fbc9efb81191ccba58debc18aae03fbec7048a59624284377b/hiredis-3.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f444c482e817452ccb598140c6544c803480346f572e0b42fece391ed70ff26", size = 42606 }, - { url = "https://files.pythonhosted.org/packages/dc/62/43f9b533bc1020814e0edab0b26ff473b63723a76fb4939c07f5693ba3a5/hiredis-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c63a753a0ba0bb0bc92041682623cab843114a0cf87875cd9aca0ab0d833337", size = 170110 }, - { url = "https://files.pythonhosted.org/packages/dd/6d/6d186f2c0faa486f2615c10f78d85969999118115564fe5efa7ba36c2cbe/hiredis-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93f1981e0f54e74de525266a2dca3f9740ca2eed03227b4f86d1ae8ef887d37b", size = 181043 }, - { url = "https://files.pythonhosted.org/packages/65/b0/75de93fe61a643638bbe8d8197d312a06e20ec64a92a2bcef1746e1deb68/hiredis-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0e371c78b9e4715678ca17a59fc72c37483e53179c9a2d4babf85c383fc55c5", size = 170493 }, - { url = "https://files.pythonhosted.org/packages/d9/bb/582df8cc41f0ab52c364eaf8ba0515a952c757d41d5f3e44d7b1bcc4eda4/hiredis-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d42cd753d4d85cf806037a01e4e6fa83c8db5b20b8d0cbfc2feec3daad2d563f", size = 171187 }, - { url = "https://files.pythonhosted.org/packages/7a/46/46704ab52f3a334d5340d121f0692196059b31af27d1dde9279a79c897ba/hiredis-3.1.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76b8f64de36c8607650c47951a1591996dcfe186ae158f88bac7e3976348cccc", size = 166707 }, - { url = "https://files.pythonhosted.org/packages/1a/c2/50bbca04b21dd6bf208c429348230a0ef7d64091d3ee4ff2ad54fb204efe/hiredis-3.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1a6f2e54bbad9e0831c5d88451676d7f116210f4f302055a84671ef69c5e935b", size = 164293 }, - { url = "https://files.pythonhosted.org/packages/c1/07/157078368e4262c9029e8254f287ea851f95ec687dc78aed6d957b893af9/hiredis-3.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8619f2a015dd8ba98214e76e7453bcdaaa8b04d81348369ad8975c1ff2792eb3", size = 163146 }, - { url = "https://files.pythonhosted.org/packages/f6/1a/8bc58594b83fd4c94d8d531b061d8fc2af0a4659b5dd7bef5ad294f726d2/hiredis-3.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1fd685aa1f9636da9548fa471abf37138033f1b4ec0d91f515ea5ed4d7d88b62", size = 175236 }, - { url = "https://files.pythonhosted.org/packages/3a/b1/8f7fc62699b11adb453f91fc33bf738a8b73b38274bc392f24b9b2b1e2ff/hiredis-3.1.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:24b51d492b6628054eb4dce63eab0cadf483b87227fe6ee3b6de0038caed6544", size = 167789 }, - { url = "https://files.pythonhosted.org/packages/f5/ab/35715b22dc1962bf6edf0dcde5fe62ca35221c81fe5b946a38e0da4d2f93/hiredis-3.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0c7e43d3968000d75d97b2d24a6f1ee37d24b9a4472ba85f670e7d2d94c6b1f2", size = 165724 }, - { url = "https://files.pythonhosted.org/packages/09/7f/345923dba3b9d6326accd20bddebe5a0a40abe28447581188a5da2c720eb/hiredis-3.1.1-cp312-cp312-win32.whl", hash = "sha256:b48578047c6bb3d0ea3ce37f0762e35e71d1f7cff8d940e2caa131359a12c5a7", size = 20191 }, - { url = "https://files.pythonhosted.org/packages/92/f0/856832bf2558f35ea4db0d594176cf61b10dd6091d9029542362c29631d8/hiredis-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:87b69e99301a33119cb31b19c6be7aed164c0df6b6343ba57b65deb23ae9251e", size = 21796 }, +version = "3.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/08/24b72f425b75e1de7442fb1740f69ca66d5820b9f9c0e2511ff9aadab3b7/hiredis-3.2.1.tar.gz", hash = "sha256:5a5f64479bf04dd829fe7029fad0ea043eac4023abc6e946668cbbec3493a78d", size = 89096 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/84/2ea9636f2ba0811d9eb3bebbbfa84f488238180ddab70c9cb7fa13419d78/hiredis-3.2.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:e4ae0be44cab5e74e6e4c4a93d04784629a45e781ff483b136cc9e1b9c23975c", size = 82425 }, + { url = "https://files.pythonhosted.org/packages/fc/24/b9ebf766a99998fda3975937afa4912e98de9d7f8d0b83f48096bdd961c1/hiredis-3.2.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:24647e84c9f552934eb60b7f3d2116f8b64a7020361da9369e558935ca45914d", size = 45231 }, + { url = "https://files.pythonhosted.org/packages/68/4c/c009b4d9abeb964d607f0987561892d1589907f770b9e5617552b34a4a4d/hiredis-3.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6fb3e92d1172da8decc5f836bf8b528c0fc9b6d449f1353e79ceeb9dc1801132", size = 43240 }, + { url = "https://files.pythonhosted.org/packages/e9/83/d53f3ae9e4ac51b8a35afb7ccd68db871396ed1d7c8ba02ce2c30de0cf17/hiredis-3.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38ba7a32e51e518b6b3e470142e52ed2674558e04d7d73d86eb19ebcb37d7d40", size = 169624 }, + { url = "https://files.pythonhosted.org/packages/91/2f/f9f091526e22a45385d45f3870204dc78aee365b6fe32e679e65674da6a7/hiredis-3.2.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4fc632be73174891d6bb71480247e57b2fd8f572059f0a1153e4d0339e919779", size = 165799 }, + { url = "https://files.pythonhosted.org/packages/1c/cc/e561274438cdb19794f0638136a5a99a9ca19affcb42679b12a78016b8ad/hiredis-3.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f03e6839ff21379ad3c195e0700fc9c209e7f344946dea0f8a6d7b5137a2a141", size = 180612 }, + { url = "https://files.pythonhosted.org/packages/83/ba/a8a989f465191d55672e57aea2a331bfa3a74b5cbc6f590031c9e11f7491/hiredis-3.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99983873e37c71bb71deb544670ff4f9d6920dab272aaf52365606d87a4d6c73", size = 169934 }, + { url = "https://files.pythonhosted.org/packages/52/5f/1148e965df1c67b17bdcaef199f54aec3def0955d19660a39c6ee10a6f55/hiredis-3.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffd982c419f48e3a57f592678c72474429465bb4bfc96472ec805f5d836523f0", size = 170074 }, + { url = "https://files.pythonhosted.org/packages/43/5e/e6846ad159a938b539fb8d472e2e68cb6758d7c9454ea0520211f335ea72/hiredis-3.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bc993f4aa4abc029347f309e722f122e05a3b8a0c279ae612849b5cc9dc69f2d", size = 164158 }, + { url = "https://files.pythonhosted.org/packages/0a/a1/5891e0615f0993f194c1b51a65aaac063b0db318a70df001b28e49f0579d/hiredis-3.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dde790d420081f18b5949227649ccb3ed991459df33279419a25fcae7f97cd92", size = 162591 }, + { url = "https://files.pythonhosted.org/packages/d4/da/8bce52ca81716f53c1014f689aea4c170ba6411e6848f81a1bed1fc375eb/hiredis-3.2.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b0c8cae7edbef860afcf3177b705aef43e10b5628f14d5baf0ec69668247d08d", size = 174808 }, + { url = "https://files.pythonhosted.org/packages/84/91/fc1ef444ed4dc432b5da9b48e9bd23266c703528db7be19e2b608d67ba06/hiredis-3.2.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e8a90eaca7e1ce7f175584f07a2cdbbcab13f4863f9f355d7895c4d28805f65b", size = 167060 }, + { url = "https://files.pythonhosted.org/packages/66/ad/beebf73a5455f232b97e00564d1e8ad095d4c6e18858c60c6cfdd893ac1e/hiredis-3.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:476031958fa44e245e803827e0787d49740daa4de708fe514370293ce519893a", size = 164833 }, + { url = "https://files.pythonhosted.org/packages/75/79/a9591bdc0148c0fbdf54cf6f3d449932d3b3b8779e87f33fa100a5a8088f/hiredis-3.2.1-cp311-cp311-win32.whl", hash = "sha256:eb3f5df2a9593b4b4b676dce3cea53b9c6969fc372875188589ddf2bafc7f624", size = 20402 }, + { url = "https://files.pythonhosted.org/packages/9f/05/c93cc6fab31e3c01b671126c82f44372fb211facb8bd4571fd372f50898d/hiredis-3.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:1402e763d8a9fdfcc103bbf8b2913971c0a3f7b8a73deacbda3dfe5f3a9d1e0b", size = 22085 }, + { url = "https://files.pythonhosted.org/packages/60/a1/6da1578a22df1926497f7a3f6a3d2408fe1d1559f762c1640af5762a8eb6/hiredis-3.2.1-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:3742d8b17e73c198cabeab11da35f2e2a81999d406f52c6275234592256bf8e8", size = 82627 }, + { url = "https://files.pythonhosted.org/packages/6c/b1/1056558ca8dc330be5bb25162fe5f268fee71571c9a535153df9f871a073/hiredis-3.2.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9c2f3176fb617a79f6cccf22cb7d2715e590acb534af6a82b41f8196ad59375d", size = 45404 }, + { url = "https://files.pythonhosted.org/packages/58/4f/13d1fa1a6b02a99e9fed8f546396f2d598c3613c98e6c399a3284fa65361/hiredis-3.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a8bd46189c7fa46174e02670dc44dfecb60f5bd4b67ed88cb050d8f1fd842f09", size = 43299 }, + { url = "https://files.pythonhosted.org/packages/c0/25/ddfac123ba5a32eb1f0b40ba1b2ec98a599287f7439def8856c3c7e5dd0d/hiredis-3.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f86ee4488c8575b58139cdfdddeae17f91e9a893ffee20260822add443592e2f", size = 172194 }, + { url = "https://files.pythonhosted.org/packages/2c/1e/443a3703ce570b631ca43494094fbaeb051578a0ebe4bfcefde351e1ba25/hiredis-3.2.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3717832f4a557b2fe7060b9d4a7900e5de287a15595e398c3f04df69019ca69d", size = 168429 }, + { url = "https://files.pythonhosted.org/packages/3b/d6/0d8c6c706ed79b2298c001b5458c055615e3166533dcee3900e821a18a3e/hiredis-3.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e5cb12c21fb9e2403d28c4e6a38120164973342d34d08120f2d7009b66785644", size = 182967 }, + { url = "https://files.pythonhosted.org/packages/da/68/da8dd231fbce858b5a20ab7d7bf558912cd125f08bac4c778865ef5fe2c2/hiredis-3.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:080fda1510bbd389af91f919c11a4f2aa4d92f0684afa4709236faa084a42cac", size = 172495 }, + { url = "https://files.pythonhosted.org/packages/65/25/83a31420535e2778662caa95533d5c997011fa6a88331f0cdb22afea9ec3/hiredis-3.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1252e10a1f3273d1c6bf2021e461652c2e11b05b83e0915d6eb540ec7539afe2", size = 173142 }, + { url = "https://files.pythonhosted.org/packages/41/d7/cb907348889eb75e2aa2e6b63e065b611459e0f21fe1e371a968e13f0d55/hiredis-3.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d9e320e99ab7d2a30dc91ff6f745ba38d39b23f43d345cdee9881329d7b511d6", size = 166433 }, + { url = "https://files.pythonhosted.org/packages/01/5d/7cbc69d82af7b29a95723d50f5261555ba3d024bfbdc414bdc3d23c0defb/hiredis-3.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:641668f385f16550fdd6fdc109b0af6988b94ba2acc06770a5e06a16e88f320c", size = 164883 }, + { url = "https://files.pythonhosted.org/packages/f9/00/f995b1296b1d7e0247651347aa230f3225a9800e504fdf553cf7cd001cf7/hiredis-3.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1e1f44208c39d6c345ff451f82f21e9eeda6fe9af4ac65972cc3eeb58d41f7cb", size = 177262 }, + { url = "https://files.pythonhosted.org/packages/c5/f3/723a67d729e94764ce9e0d73fa5f72a0f87d3ce3c98c9a0b27cbf001cc79/hiredis-3.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f882a0d6415fffe1ffcb09e6281d0ba8b1ece470e866612bbb24425bf76cf397", size = 169619 }, + { url = "https://files.pythonhosted.org/packages/45/58/f69028df00fb1b223e221403f3be2059ae86031e7885f955d26236bdfc17/hiredis-3.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b4e78719a0730ebffe335528531d154bc8867a246418f74ecd88adbc4d938c49", size = 167303 }, + { url = "https://files.pythonhosted.org/packages/2b/7d/567411e65cce76cf265a9a4f837fd2ebc564bef6368dd42ac03f7a517c0a/hiredis-3.2.1-cp312-cp312-win32.whl", hash = "sha256:33c4604d9f79a13b84da79950a8255433fca7edaf292bbd3364fd620864ed7b2", size = 20551 }, + { url = "https://files.pythonhosted.org/packages/90/74/b4c291eb4a4a874b3690ff9fc311a65d5292072556421b11b1d786e3e1d0/hiredis-3.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7b9749375bf9d171aab8813694f379f2cff0330d7424000f5e92890ad4932dc9", size = 22128 }, ] [[package]] @@ -2526,7 +2508,7 @@ socks = [ [[package]] name = "huggingface-hub" -version = "0.31.1" +version = "0.32.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, @@ -2538,9 +2520,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/eb/9268c1205d19388659d5dc664f012177b752c0eef194a9159acc7227780f/huggingface_hub-0.31.1.tar.gz", hash = "sha256:492bb5f545337aa9e2f59b75ef4c5f535a371e8958a6ce90af056387e67f1180", size = 403036 } +sdist = { url = "https://files.pythonhosted.org/packages/59/74/c4961b31e0f142a032ea24f477c3a7524dfabfd8126398a968b3cc6bf804/huggingface_hub-0.32.3.tar.gz", hash = "sha256:752c889ebf3a63cbd39803f6d87ccc135a463bbcb36abfa2faff0ccbf1cec087", size = 424525 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bf/6002da17ec1c7a47bedeb216812929665927c70b6e7500b3c7bf36f01bdd/huggingface_hub-0.31.1-py3-none-any.whl", hash = "sha256:43f73124819b48b42d140cbc0d7a2e6bd15b2853b1b9d728d4d55ad1750cac5b", size = 484265 }, + { url = "https://files.pythonhosted.org/packages/df/dc/4f4d8080cbce7a38c1d0f1ba4932f9134480b9761af8ef4c65d49254b2bd/huggingface_hub-0.32.3-py3-none-any.whl", hash = "sha256:e46f7ea7fe2b5e5f67cc4e37eb201140091946a314d7c2b134a9673dadd80b6a", size = 512094 }, ] [[package]] @@ -2641,34 +2623,34 @@ wheels = [ [[package]] name = "jiter" -version = "0.9.0" +version = "0.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/c2/e4562507f52f0af7036da125bb699602ead37a2332af0788f8e0a3417f36/jiter-0.9.0.tar.gz", hash = "sha256:aadba0964deb424daa24492abc3d229c60c4a31bfee205aedbf1acc7639d7893", size = 162604 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/44/e241a043f114299254e44d7e777ead311da400517f179665e59611ab0ee4/jiter-0.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6c4d99c71508912a7e556d631768dcdef43648a93660670986916b297f1c54af", size = 314654 }, - { url = "https://files.pythonhosted.org/packages/fb/1b/a7e5e42db9fa262baaa9489d8d14ca93f8663e7f164ed5e9acc9f467fc00/jiter-0.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8f60fb8ce7df529812bf6c625635a19d27f30806885139e367af93f6e734ef58", size = 320909 }, - { url = "https://files.pythonhosted.org/packages/60/bf/8ebdfce77bc04b81abf2ea316e9c03b4a866a7d739cf355eae4d6fd9f6fe/jiter-0.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51c4e1a4f8ea84d98b7b98912aa4290ac3d1eabfde8e3c34541fae30e9d1f08b", size = 341733 }, - { url = "https://files.pythonhosted.org/packages/a8/4e/754ebce77cff9ab34d1d0fa0fe98f5d42590fd33622509a3ba6ec37ff466/jiter-0.9.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f4c677c424dc76684fea3e7285a7a2a7493424bea89ac441045e6a1fb1d7b3b", size = 365097 }, - { url = "https://files.pythonhosted.org/packages/32/2c/6019587e6f5844c612ae18ca892f4cd7b3d8bbf49461ed29e384a0f13d98/jiter-0.9.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2221176dfec87f3470b21e6abca056e6b04ce9bff72315cb0b243ca9e835a4b5", size = 406603 }, - { url = "https://files.pythonhosted.org/packages/da/e9/c9e6546c817ab75a1a7dab6dcc698e62e375e1017113e8e983fccbd56115/jiter-0.9.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c7adb66f899ffa25e3c92bfcb593391ee1947dbdd6a9a970e0d7e713237d572", size = 396625 }, - { url = "https://files.pythonhosted.org/packages/be/bd/976b458add04271ebb5a255e992bd008546ea04bb4dcadc042a16279b4b4/jiter-0.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c98d27330fdfb77913c1097a7aab07f38ff2259048949f499c9901700789ac15", size = 351832 }, - { url = "https://files.pythonhosted.org/packages/07/51/fe59e307aaebec9265dbad44d9d4381d030947e47b0f23531579b9a7c2df/jiter-0.9.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eda3f8cc74df66892b1d06b5d41a71670c22d95a1ca2cbab73654745ce9d0419", size = 384590 }, - { url = "https://files.pythonhosted.org/packages/db/55/5dcd2693794d8e6f4889389ff66ef3be557a77f8aeeca8973a97a7c00557/jiter-0.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dd5ab5ddc11418dce28343123644a100f487eaccf1de27a459ab36d6cca31043", size = 520690 }, - { url = "https://files.pythonhosted.org/packages/54/d5/9f51dc90985e9eb251fbbb747ab2b13b26601f16c595a7b8baba964043bd/jiter-0.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:42f8a68a69f047b310319ef8e2f52fdb2e7976fb3313ef27df495cf77bcad965", size = 512649 }, - { url = "https://files.pythonhosted.org/packages/a6/e5/4e385945179bcf128fa10ad8dca9053d717cbe09e258110e39045c881fe5/jiter-0.9.0-cp311-cp311-win32.whl", hash = "sha256:a25519efb78a42254d59326ee417d6f5161b06f5da827d94cf521fed961b1ff2", size = 206920 }, - { url = "https://files.pythonhosted.org/packages/4c/47/5e0b94c603d8e54dd1faab439b40b832c277d3b90743e7835879ab663757/jiter-0.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:923b54afdd697dfd00d368b7ccad008cccfeb1efb4e621f32860c75e9f25edbd", size = 210119 }, - { url = "https://files.pythonhosted.org/packages/af/d7/c55086103d6f29b694ec79156242304adf521577530d9031317ce5338c59/jiter-0.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7b46249cfd6c48da28f89eb0be3f52d6fdb40ab88e2c66804f546674e539ec11", size = 309203 }, - { url = "https://files.pythonhosted.org/packages/b0/01/f775dfee50beb420adfd6baf58d1c4d437de41c9b666ddf127c065e5a488/jiter-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:609cf3c78852f1189894383cf0b0b977665f54cb38788e3e6b941fa6d982c00e", size = 319678 }, - { url = "https://files.pythonhosted.org/packages/ab/b8/09b73a793714726893e5d46d5c534a63709261af3d24444ad07885ce87cb/jiter-0.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d726a3890a54561e55a9c5faea1f7655eda7f105bd165067575ace6e65f80bb2", size = 341816 }, - { url = "https://files.pythonhosted.org/packages/35/6f/b8f89ec5398b2b0d344257138182cc090302854ed63ed9c9051e9c673441/jiter-0.9.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2e89dc075c1fef8fa9be219e249f14040270dbc507df4215c324a1839522ea75", size = 364152 }, - { url = "https://files.pythonhosted.org/packages/9b/ca/978cc3183113b8e4484cc7e210a9ad3c6614396e7abd5407ea8aa1458eef/jiter-0.9.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04e8ffa3c353b1bc4134f96f167a2082494351e42888dfcf06e944f2729cbe1d", size = 406991 }, - { url = "https://files.pythonhosted.org/packages/13/3a/72861883e11a36d6aa314b4922125f6ae90bdccc225cd96d24cc78a66385/jiter-0.9.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:203f28a72a05ae0e129b3ed1f75f56bc419d5f91dfacd057519a8bd137b00c42", size = 395824 }, - { url = "https://files.pythonhosted.org/packages/87/67/22728a86ef53589c3720225778f7c5fdb617080e3deaed58b04789418212/jiter-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fca1a02ad60ec30bb230f65bc01f611c8608b02d269f998bc29cca8619a919dc", size = 351318 }, - { url = "https://files.pythonhosted.org/packages/69/b9/f39728e2e2007276806d7a6609cda7fac44ffa28ca0d02c49a4f397cc0d9/jiter-0.9.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:237e5cee4d5d2659aaf91bbf8ec45052cc217d9446070699441a91b386ae27dc", size = 384591 }, - { url = "https://files.pythonhosted.org/packages/eb/8f/8a708bc7fd87b8a5d861f1c118a995eccbe6d672fe10c9753e67362d0dd0/jiter-0.9.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:528b6b71745e7326eed73c53d4aa57e2a522242320b6f7d65b9c5af83cf49b6e", size = 520746 }, - { url = "https://files.pythonhosted.org/packages/95/1e/65680c7488bd2365dbd2980adaf63c562d3d41d3faac192ebc7ef5b4ae25/jiter-0.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9f48e86b57bc711eb5acdfd12b6cb580a59cc9a993f6e7dcb6d8b50522dcd50d", size = 512754 }, - { url = "https://files.pythonhosted.org/packages/78/f3/fdc43547a9ee6e93c837685da704fb6da7dba311fc022e2766d5277dfde5/jiter-0.9.0-cp312-cp312-win32.whl", hash = "sha256:699edfde481e191d81f9cf6d2211debbfe4bd92f06410e7637dffb8dd5dfde06", size = 207075 }, - { url = "https://files.pythonhosted.org/packages/cd/9d/742b289016d155f49028fe1bfbeb935c9bf0ffeefdf77daf4a63a42bb72b/jiter-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:099500d07b43f61d8bd780466d429c45a7b25411b334c60ca875fa775f68ccb0", size = 207999 }, +sdist = { url = "https://files.pythonhosted.org/packages/ee/9d/ae7ddb4b8ab3fb1b51faf4deb36cb48a4fbbd7cb36bad6a5fca4741306f7/jiter-0.10.0.tar.gz", hash = "sha256:07a7142c38aacc85194391108dc91b5b57093c978a9932bd86a36862759d9500", size = 162759 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/dd/6cefc6bd68b1c3c979cecfa7029ab582b57690a31cd2f346c4d0ce7951b6/jiter-0.10.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3bebe0c558e19902c96e99217e0b8e8b17d570906e72ed8a87170bc290b1e978", size = 317473 }, + { url = "https://files.pythonhosted.org/packages/be/cf/fc33f5159ce132be1d8dd57251a1ec7a631c7df4bd11e1cd198308c6ae32/jiter-0.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:558cc7e44fd8e507a236bee6a02fa17199ba752874400a0ca6cd6e2196cdb7dc", size = 321971 }, + { url = "https://files.pythonhosted.org/packages/68/a4/da3f150cf1d51f6c472616fb7650429c7ce053e0c962b41b68557fdf6379/jiter-0.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d613e4b379a07d7c8453c5712ce7014e86c6ac93d990a0b8e7377e18505e98d", size = 345574 }, + { url = "https://files.pythonhosted.org/packages/84/34/6e8d412e60ff06b186040e77da5f83bc158e9735759fcae65b37d681f28b/jiter-0.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f62cf8ba0618eda841b9bf61797f21c5ebd15a7a1e19daab76e4e4b498d515b2", size = 371028 }, + { url = "https://files.pythonhosted.org/packages/fb/d9/9ee86173aae4576c35a2f50ae930d2ccb4c4c236f6cb9353267aa1d626b7/jiter-0.10.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:919d139cdfa8ae8945112398511cb7fca58a77382617d279556b344867a37e61", size = 491083 }, + { url = "https://files.pythonhosted.org/packages/d9/2c/f955de55e74771493ac9e188b0f731524c6a995dffdcb8c255b89c6fb74b/jiter-0.10.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13ddbc6ae311175a3b03bd8994881bc4635c923754932918e18da841632349db", size = 388821 }, + { url = "https://files.pythonhosted.org/packages/81/5a/0e73541b6edd3f4aada586c24e50626c7815c561a7ba337d6a7eb0a915b4/jiter-0.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c440ea003ad10927a30521a9062ce10b5479592e8a70da27f21eeb457b4a9c5", size = 352174 }, + { url = "https://files.pythonhosted.org/packages/1c/c0/61eeec33b8c75b31cae42be14d44f9e6fe3ac15a4e58010256ac3abf3638/jiter-0.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc347c87944983481e138dea467c0551080c86b9d21de6ea9306efb12ca8f606", size = 391869 }, + { url = "https://files.pythonhosted.org/packages/41/22/5beb5ee4ad4ef7d86f5ea5b4509f680a20706c4a7659e74344777efb7739/jiter-0.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:13252b58c1f4d8c5b63ab103c03d909e8e1e7842d302473f482915d95fefd605", size = 523741 }, + { url = "https://files.pythonhosted.org/packages/ea/10/768e8818538e5817c637b0df52e54366ec4cebc3346108a4457ea7a98f32/jiter-0.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7d1bbf3c465de4a24ab12fb7766a0003f6f9bce48b8b6a886158c4d569452dc5", size = 514527 }, + { url = "https://files.pythonhosted.org/packages/73/6d/29b7c2dc76ce93cbedabfd842fc9096d01a0550c52692dfc33d3cc889815/jiter-0.10.0-cp311-cp311-win32.whl", hash = "sha256:db16e4848b7e826edca4ccdd5b145939758dadf0dc06e7007ad0e9cfb5928ae7", size = 210765 }, + { url = "https://files.pythonhosted.org/packages/c2/c9/d394706deb4c660137caf13e33d05a031d734eb99c051142e039d8ceb794/jiter-0.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c9c1d5f10e18909e993f9641f12fe1c77b3e9b533ee94ffa970acc14ded3812", size = 209234 }, + { url = "https://files.pythonhosted.org/packages/6d/b5/348b3313c58f5fbfb2194eb4d07e46a35748ba6e5b3b3046143f3040bafa/jiter-0.10.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1e274728e4a5345a6dde2d343c8da018b9d4bd4350f5a472fa91f66fda44911b", size = 312262 }, + { url = "https://files.pythonhosted.org/packages/9c/4a/6a2397096162b21645162825f058d1709a02965606e537e3304b02742e9b/jiter-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7202ae396446c988cb2a5feb33a543ab2165b786ac97f53b59aafb803fef0744", size = 320124 }, + { url = "https://files.pythonhosted.org/packages/2a/85/1ce02cade7516b726dd88f59a4ee46914bf79d1676d1228ef2002ed2f1c9/jiter-0.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23ba7722d6748b6920ed02a8f1726fb4b33e0fd2f3f621816a8b486c66410ab2", size = 345330 }, + { url = "https://files.pythonhosted.org/packages/75/d0/bb6b4f209a77190ce10ea8d7e50bf3725fc16d3372d0a9f11985a2b23eff/jiter-0.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:371eab43c0a288537d30e1f0b193bc4eca90439fc08a022dd83e5e07500ed026", size = 369670 }, + { url = "https://files.pythonhosted.org/packages/a0/f5/a61787da9b8847a601e6827fbc42ecb12be2c925ced3252c8ffcb56afcaf/jiter-0.10.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c675736059020365cebc845a820214765162728b51ab1e03a1b7b3abb70f74c", size = 489057 }, + { url = "https://files.pythonhosted.org/packages/12/e4/6f906272810a7b21406c760a53aadbe52e99ee070fc5c0cb191e316de30b/jiter-0.10.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c5867d40ab716e4684858e4887489685968a47e3ba222e44cde6e4a2154f959", size = 389372 }, + { url = "https://files.pythonhosted.org/packages/e2/ba/77013b0b8ba904bf3762f11e0129b8928bff7f978a81838dfcc958ad5728/jiter-0.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395bb9a26111b60141757d874d27fdea01b17e8fac958b91c20128ba8f4acc8a", size = 352038 }, + { url = "https://files.pythonhosted.org/packages/67/27/c62568e3ccb03368dbcc44a1ef3a423cb86778a4389e995125d3d1aaa0a4/jiter-0.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6842184aed5cdb07e0c7e20e5bdcfafe33515ee1741a6835353bb45fe5d1bd95", size = 391538 }, + { url = "https://files.pythonhosted.org/packages/c0/72/0d6b7e31fc17a8fdce76164884edef0698ba556b8eb0af9546ae1a06b91d/jiter-0.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:62755d1bcea9876770d4df713d82606c8c1a3dca88ff39046b85a048566d56ea", size = 523557 }, + { url = "https://files.pythonhosted.org/packages/2f/09/bc1661fbbcbeb6244bd2904ff3a06f340aa77a2b94e5a7373fd165960ea3/jiter-0.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533efbce2cacec78d5ba73a41756beff8431dfa1694b6346ce7af3a12c42202b", size = 514202 }, + { url = "https://files.pythonhosted.org/packages/1b/84/5a5d5400e9d4d54b8004c9673bbe4403928a00d28529ff35b19e9d176b19/jiter-0.10.0-cp312-cp312-win32.whl", hash = "sha256:8be921f0cadd245e981b964dfbcd6fd4bc4e254cdc069490416dd7a2632ecc01", size = 211781 }, + { url = "https://files.pythonhosted.org/packages/9b/52/7ec47455e26f2d6e5f2ea4951a0652c06e5b995c291f723973ae9e724a65/jiter-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7c7d785ae9dda68c2678532a5a1581347e9c15362ae9f6e68f3fdbfb64f2e49", size = 206176 }, ] [[package]] @@ -2682,25 +2664,25 @@ wheels = [ [[package]] name = "joblib" -version = "1.5.0" +version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/08/8bd4a0250247861420a040b33ccf42f43c426ac91d99405374ef117e5872/joblib-1.5.0.tar.gz", hash = "sha256:d8757f955389a3dd7a23152e43bc297c2e0c2d3060056dad0feefc88a06939b5", size = 330234 } +sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475 } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/d3/13ee227a148af1c693654932b8b0b02ed64af5e1f7406d56b088b57574cd/joblib-1.5.0-py3-none-any.whl", hash = "sha256:206144b320246485b712fc8cc51f017de58225fa8b414a1fe1764a7231aca491", size = 307682 }, + { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746 }, ] [[package]] name = "json-repair" -version = "0.44.1" +version = "0.46.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a8/6b/ed6e92efc5acfbc9c35ccae1676b70e4adb1552421e64f838c2a3f097d9a/json_repair-0.44.1.tar.gz", hash = "sha256:1130eb9733b868dac1340b43cb2effebb519ae6d52dd2d0728c6cca517f1e0b4", size = 32886 } +sdist = { url = "https://files.pythonhosted.org/packages/79/5a/5c14f14735438eb27fd4eb9bb4eb273c996c0d1d959182382cbc618f99dd/json_repair-0.46.0.tar.gz", hash = "sha256:abc751162baf8e384685558acba978478e833c1207be31468d9babfaf8029ab6", size = 33321 } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/b4/3cbd27a3240b2962c3b87bbb1c20eb6c56e5b26cde61f141f86ca98e2f68/json_repair-0.44.1-py3-none-any.whl", hash = "sha256:51d82532c3b8263782a301eb7904c75dce5fee8c0d1aba490287fc0ab779ac50", size = 22478 }, + { url = "https://files.pythonhosted.org/packages/33/ea/8ca71883f10acf4449720b86dd85cea51d7a71bec2558d5275ae0dcc66e4/json_repair-0.46.0-py3-none-any.whl", hash = "sha256:54d6a9889fba0846b80befb2b1aca619103ad3ed74612fb3fedd965a4a3b1653", size = 22255 }, ] [[package]] name = "jsonschema" -version = "4.23.0" +version = "4.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -2708,9 +2690,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778 } +sdist = { url = "https://files.pythonhosted.org/packages/bf/d3/1cf5326b923a53515d8f3a2cd442e6d7e94fcc444716e879ea70a0ce3177/jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196", size = 353480 } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462 }, + { url = "https://files.pythonhosted.org/packages/a2/3d/023389198f69c722d039351050738d6755376c8fd343e91dc493ea485905/jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d", size = 88709 }, ] [[package]] @@ -2727,16 +2709,17 @@ wheels = [ [[package]] name = "kombu" -version = "5.5.3" +version = "5.5.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "amqp" }, + { name = "packaging" }, { name = "tzdata" }, { name = "vine" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/60/0a/128b65651ed8120460fc5af754241ad595eac74993115ec0de4f2d7bc459/kombu-5.5.3.tar.gz", hash = "sha256:021a0e11fcfcd9b0260ef1fb64088c0e92beb976eb59c1dfca7ddd4ad4562ea2", size = 461784 } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d3/5ff936d8319ac86b9c409f1501b07c426e6ad41966fedace9ef1b966e23f/kombu-5.5.4.tar.gz", hash = "sha256:886600168275ebeada93b888e831352fe578168342f0d1d5833d88ba0d847363", size = 461992 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/35/1407fb0b2f5b07b50cbaf97fce09ad87d3bfefbf64f7171a8651cd8d2f68/kombu-5.5.3-py3-none-any.whl", hash = "sha256:5b0dbceb4edee50aa464f59469d34b97864be09111338cfb224a10b6a163909b", size = 209921 }, + { url = "https://files.pythonhosted.org/packages/ef/70/a07dcf4f62598c8ad579df241af55ced65bed76e42e45d3c368a6d82dbc1/kombu-5.5.4-py3-none-any.whl", hash = "sha256:a12ed0557c238897d8e518f1d1fdf84bd1516c5e305af2dacd85c2015115feb8", size = 210034 }, ] [[package]] @@ -3170,45 +3153,45 @@ wheels = [ [[package]] name = "multidict" -version = "6.4.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/2c/e367dfb4c6538614a0c9453e510d75d66099edf1c4e69da1b5ce691a1931/multidict-6.4.3.tar.gz", hash = "sha256:3ada0b058c9f213c5f95ba301f922d402ac234f1111a7d8fd70f1b99f3c281ec", size = 89372 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/16/e0/53cf7f27eda48fffa53cfd4502329ed29e00efb9e4ce41362cbf8aa54310/multidict-6.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f6f19170197cc29baccd33ccc5b5d6a331058796485857cf34f7635aa25fb0cd", size = 65259 }, - { url = "https://files.pythonhosted.org/packages/44/79/1dcd93ce7070cf01c2ee29f781c42b33c64fce20033808f1cc9ec8413d6e/multidict-6.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f2882bf27037eb687e49591690e5d491e677272964f9ec7bc2abbe09108bdfb8", size = 38451 }, - { url = "https://files.pythonhosted.org/packages/f4/35/2292cf29ab5f0d0b3613fad1b75692148959d3834d806be1885ceb49a8ff/multidict-6.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fbf226ac85f7d6b6b9ba77db4ec0704fde88463dc17717aec78ec3c8546c70ad", size = 37706 }, - { url = "https://files.pythonhosted.org/packages/f6/d1/6b157110b2b187b5a608b37714acb15ee89ec773e3800315b0107ea648cd/multidict-6.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e329114f82ad4b9dd291bef614ea8971ec119ecd0f54795109976de75c9a852", size = 226669 }, - { url = "https://files.pythonhosted.org/packages/40/7f/61a476450651f177c5570e04bd55947f693077ba7804fe9717ee9ae8de04/multidict-6.4.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1f4e0334d7a555c63f5c8952c57ab6f1c7b4f8c7f3442df689fc9f03df315c08", size = 223182 }, - { url = "https://files.pythonhosted.org/packages/51/7b/eaf7502ac4824cdd8edcf5723e2e99f390c879866aec7b0c420267b53749/multidict-6.4.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:740915eb776617b57142ce0bb13b7596933496e2f798d3d15a20614adf30d229", size = 235025 }, - { url = "https://files.pythonhosted.org/packages/3b/f6/facdbbd73c96b67a93652774edd5778ab1167854fa08ea35ad004b1b70ad/multidict-6.4.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255dac25134d2b141c944b59a0d2f7211ca12a6d4779f7586a98b4b03ea80508", size = 231481 }, - { url = "https://files.pythonhosted.org/packages/70/57/c008e861b3052405eebf921fd56a748322d8c44dcfcab164fffbccbdcdc4/multidict-6.4.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4e8535bd4d741039b5aad4285ecd9b902ef9e224711f0b6afda6e38d7ac02c7", size = 223492 }, - { url = "https://files.pythonhosted.org/packages/30/4d/7d8440d3a12a6ae5d6b202d6e7f2ac6ab026e04e99aaf1b73f18e6bc34bc/multidict-6.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c433a33be000dd968f5750722eaa0991037be0be4a9d453eba121774985bc8", size = 217279 }, - { url = "https://files.pythonhosted.org/packages/7f/e7/bca0df4dd057597b94138d2d8af04eb3c27396a425b1b0a52e082f9be621/multidict-6.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4eb33b0bdc50acd538f45041f5f19945a1f32b909b76d7b117c0c25d8063df56", size = 228733 }, - { url = "https://files.pythonhosted.org/packages/88/f5/383827c3f1c38d7c92dbad00a8a041760228573b1c542fbf245c37bbca8a/multidict-6.4.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:75482f43465edefd8a5d72724887ccdcd0c83778ded8f0cb1e0594bf71736cc0", size = 218089 }, - { url = "https://files.pythonhosted.org/packages/36/8a/a5174e8a7d8b94b4c8f9c1e2cf5d07451f41368ffe94d05fc957215b8e72/multidict-6.4.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce5b3082e86aee80b3925ab4928198450d8e5b6466e11501fe03ad2191c6d777", size = 225257 }, - { url = "https://files.pythonhosted.org/packages/8c/76/1d4b7218f0fd00b8e5c90b88df2e45f8af127f652f4e41add947fa54c1c4/multidict-6.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e413152e3212c4d39f82cf83c6f91be44bec9ddea950ce17af87fbf4e32ca6b2", size = 234728 }, - { url = "https://files.pythonhosted.org/packages/64/44/18372a4f6273fc7ca25630d7bf9ae288cde64f29593a078bff450c7170b6/multidict-6.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8aac2eeff69b71f229a405c0a4b61b54bade8e10163bc7b44fcd257949620618", size = 230087 }, - { url = "https://files.pythonhosted.org/packages/0f/ae/28728c314a698d8a6d9491fcacc897077348ec28dd85884d09e64df8a855/multidict-6.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ab583ac203af1d09034be41458feeab7863c0635c650a16f15771e1386abf2d7", size = 223137 }, - { url = "https://files.pythonhosted.org/packages/22/50/785bb2b3fe16051bc91c70a06a919f26312da45c34db97fc87441d61e343/multidict-6.4.3-cp311-cp311-win32.whl", hash = "sha256:1b2019317726f41e81154df636a897de1bfe9228c3724a433894e44cd2512378", size = 34959 }, - { url = "https://files.pythonhosted.org/packages/2f/63/2a22e099ae2f4d92897618c00c73a09a08a2a9aa14b12736965bf8d59fd3/multidict-6.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:43173924fa93c7486402217fab99b60baf78d33806af299c56133a3755f69589", size = 38541 }, - { url = "https://files.pythonhosted.org/packages/fc/bb/3abdaf8fe40e9226ce8a2ba5ecf332461f7beec478a455d6587159f1bf92/multidict-6.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f1c2f58f08b36f8475f3ec6f5aeb95270921d418bf18f90dffd6be5c7b0e676", size = 64019 }, - { url = "https://files.pythonhosted.org/packages/7e/b5/1b2e8de8217d2e89db156625aa0fe4a6faad98972bfe07a7b8c10ef5dd6b/multidict-6.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:26ae9ad364fc61b936fb7bf4c9d8bd53f3a5b4417142cd0be5c509d6f767e2f1", size = 37925 }, - { url = "https://files.pythonhosted.org/packages/b4/e2/3ca91c112644a395c8eae017144c907d173ea910c913ff8b62549dcf0bbf/multidict-6.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:659318c6c8a85f6ecfc06b4e57529e5a78dfdd697260cc81f683492ad7e9435a", size = 37008 }, - { url = "https://files.pythonhosted.org/packages/60/23/79bc78146c7ac8d1ac766b2770ca2e07c2816058b8a3d5da6caed8148637/multidict-6.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1eb72c741fd24d5a28242ce72bb61bc91f8451877131fa3fe930edb195f7054", size = 224374 }, - { url = "https://files.pythonhosted.org/packages/86/35/77950ed9ebd09136003a85c1926ba42001ca5be14feb49710e4334ee199b/multidict-6.4.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3cd06d88cb7398252284ee75c8db8e680aa0d321451132d0dba12bc995f0adcc", size = 230869 }, - { url = "https://files.pythonhosted.org/packages/49/97/2a33c6e7d90bc116c636c14b2abab93d6521c0c052d24bfcc231cbf7f0e7/multidict-6.4.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4543d8dc6470a82fde92b035a92529317191ce993533c3c0c68f56811164ed07", size = 231949 }, - { url = "https://files.pythonhosted.org/packages/56/ce/e9b5d9fcf854f61d6686ada7ff64893a7a5523b2a07da6f1265eaaea5151/multidict-6.4.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30a3ebdc068c27e9d6081fca0e2c33fdf132ecea703a72ea216b81a66860adde", size = 231032 }, - { url = "https://files.pythonhosted.org/packages/f0/ac/7ced59dcdfeddd03e601edb05adff0c66d81ed4a5160c443e44f2379eef0/multidict-6.4.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b038f10e23f277153f86f95c777ba1958bcd5993194fda26a1d06fae98b2f00c", size = 223517 }, - { url = "https://files.pythonhosted.org/packages/db/e6/325ed9055ae4e085315193a1b58bdb4d7fc38ffcc1f4975cfca97d015e17/multidict-6.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c605a2b2dc14282b580454b9b5d14ebe0668381a3a26d0ac39daa0ca115eb2ae", size = 216291 }, - { url = "https://files.pythonhosted.org/packages/fa/84/eeee6d477dd9dcb7691c3bb9d08df56017f5dd15c730bcc9383dcf201cf4/multidict-6.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8bd2b875f4ca2bb527fe23e318ddd509b7df163407b0fb717df229041c6df5d3", size = 228982 }, - { url = "https://files.pythonhosted.org/packages/82/94/4d1f3e74e7acf8b0c85db350e012dcc61701cd6668bc2440bb1ecb423c90/multidict-6.4.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c2e98c840c9c8e65c0e04b40c6c5066c8632678cd50c8721fdbcd2e09f21a507", size = 226823 }, - { url = "https://files.pythonhosted.org/packages/09/f0/1e54b95bda7cd01080e5732f9abb7b76ab5cc795b66605877caeb2197476/multidict-6.4.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:66eb80dd0ab36dbd559635e62fba3083a48a252633164857a1d1684f14326427", size = 222714 }, - { url = "https://files.pythonhosted.org/packages/e7/a2/f6cbca875195bd65a3e53b37ab46486f3cc125bdeab20eefe5042afa31fb/multidict-6.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c23831bdee0a2a3cf21be057b5e5326292f60472fb6c6f86392bbf0de70ba731", size = 233739 }, - { url = "https://files.pythonhosted.org/packages/79/68/9891f4d2b8569554723ddd6154375295f789dc65809826c6fb96a06314fd/multidict-6.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1535cec6443bfd80d028052e9d17ba6ff8a5a3534c51d285ba56c18af97e9713", size = 230809 }, - { url = "https://files.pythonhosted.org/packages/e6/72/a7be29ba1e87e4fc5ceb44dabc7940b8005fd2436a332a23547709315f70/multidict-6.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3b73e7227681f85d19dec46e5b881827cd354aabe46049e1a61d2f9aaa4e285a", size = 226934 }, - { url = "https://files.pythonhosted.org/packages/12/c1/259386a9ad6840ff7afc686da96808b503d152ac4feb3a96c651dc4f5abf/multidict-6.4.3-cp312-cp312-win32.whl", hash = "sha256:8eac0c49df91b88bf91f818e0a24c1c46f3622978e2c27035bfdca98e0e18124", size = 35242 }, - { url = "https://files.pythonhosted.org/packages/06/24/c8fdff4f924d37225dc0c56a28b1dca10728fc2233065fafeb27b4b125be/multidict-6.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:11990b5c757d956cd1db7cb140be50a63216af32cd6506329c2c59d732d802db", size = 38635 }, - { url = "https://files.pythonhosted.org/packages/96/10/7d526c8974f017f1e7ca584c71ee62a638e9334d8d33f27d7cdfc9ae79e4/multidict-6.4.3-py3-none-any.whl", hash = "sha256:59fe01ee8e2a1e8ceb3f6dbb216b09c8d9f4ef1c22c4fc825d045a147fa2ebc9", size = 10400 }, +version = "6.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515 }, + { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609 }, + { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871 }, + { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661 }, + { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422 }, + { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447 }, + { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455 }, + { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666 }, + { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392 }, + { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969 }, + { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433 }, + { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418 }, + { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042 }, + { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280 }, + { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322 }, + { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070 }, + { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667 }, + { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293 }, + { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096 }, + { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214 }, + { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686 }, + { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061 }, + { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412 }, + { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563 }, + { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811 }, + { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524 }, + { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012 }, + { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765 }, + { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888 }, + { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041 }, + { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046 }, + { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106 }, + { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351 }, + { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791 }, + { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481 }, ] [[package]] @@ -3361,23 +3344,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7e/80/cab10959dc1faead58dc8384a781dfbf93cb4d33d50988f7a69f1b7c9bbe/oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", size = 151688 }, ] -[[package]] -name = "oci" -version = "2.135.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "circuitbreaker" }, - { name = "cryptography" }, - { name = "pyopenssl" }, - { name = "python-dateutil" }, - { name = "pytz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/68/56/b828096e323c140edce4656b2ad073d5b662c9602c89658d4a33a9573d09/oci-2.135.2.tar.gz", hash = "sha256:520f78983c5246eae80dd5ecfd05e3a565c8b98d02ef0c1b11ba1f61bcccb61d", size = 13813532 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/fe/7a106d278f3998ea2aca65d8772736396467efd4922c56c283604dbeec5d/oci-2.135.2-py3-none-any.whl", hash = "sha256:5213319244e1c7f108bcb417322f33f01f043fd9636d4063574039f5fdf4e4f7", size = 28290849 }, -] - [[package]] name = "odfpy" version = "1.4.1" @@ -3440,15 +3406,18 @@ wheels = [ [[package]] name = "opendal" -version = "0.45.18" +version = "0.45.20" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9f/62/09ae9ab9d194e27eee24c6df87f0a5359ce73a82862d8bc429a69be8fb41/opendal-0.45.18.tar.gz", hash = "sha256:1434fff5e9ead95847596ee22ae183c6f137205d294e88d6154eae1a515fdb46", size = 982265 } +sdist = { url = "https://files.pythonhosted.org/packages/2f/3f/927dfe1349ae58b9238b8eafba747af648d660a9425f486dda01a10f0b78/opendal-0.45.20.tar.gz", hash = "sha256:9f6f90d9e9f9d6e9e5a34aa7729169ef34d2f1869ad1e01ddc39b1c0ce0c9405", size = 990267 } wheels = [ - { url = "https://files.pythonhosted.org/packages/30/8e/f23a4ed495e1c7ec47e7c23c0d58cee5726ad584d1d9212b64f39455b332/opendal-0.45.18-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9e07cfa433e69779befcca4f528b5085cc095af3308691ad4f5ebe37c28ec346", size = 26928339 }, - { url = "https://files.pythonhosted.org/packages/12/e3/7e3d2d09de3ab89f6e100d32b172ae4864dca988996e212afeec62f88214/opendal-0.45.18-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cb6d42972f9941e76b600626ed069d2c9f2bc143116a72475504550e6d387dd2", size = 12937936 }, - { url = "https://files.pythonhosted.org/packages/84/51/1b324dad0da585c7ba430449683ab6f4faa83841153d5c331b1672216229/opendal-0.45.18-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42166f049c3deae4cd406afb026ddca9e41ea1da8c7c4cd0cb76d4bdee35c87a", size = 14477843 }, - { url = "https://files.pythonhosted.org/packages/12/db/5f4d5998a5e93cbba07a99c09864e873373bc71683eda52ee4750acfcdac/opendal-0.45.18-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ae0e4ce1cf7b3c66f0b11022387dece6cc7ed7d0821a0b30f90efb41cad20d26", size = 13464183 }, - { url = "https://files.pythonhosted.org/packages/be/bb/857ebd60932c6e175a0ef4fb21a98292d9483131e411b09b3ef8bc837c18/opendal-0.45.18-cp311-abi3-win_amd64.whl", hash = "sha256:6d8d2cb268efd41a8ad20f716324e4b7f7f340e8e16f52166715dc0bef3061dc", size = 15159073 }, + { url = "https://files.pythonhosted.org/packages/84/77/6427e16b8630f0cc71f4a1b01648ed3264f1e04f1f6d9b5d09e5c6a4dd2f/opendal-0.45.20-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:35acdd8001e4a741532834fdbff3020ffb10b40028bb49fbe93c4f8197d66d8c", size = 26910966 }, + { url = "https://files.pythonhosted.org/packages/12/1f/83e415334739f1ab4dba55cdd349abf0b66612249055afb422a354b96ac8/opendal-0.45.20-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:629bfe8d384364bced6cbeb01f49b99779fa5151c68048a1869ff645ddcfcb25", size = 13002770 }, + { url = "https://files.pythonhosted.org/packages/49/94/c5de6ed54a02d7413636c2ccefa71d8dd09c2ada1cd6ecab202feb1fdeda/opendal-0.45.20-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d12cc5ac7e441fb93d86d1673112d9fb08580fc3226f864434f4a56a72efec53", size = 14387218 }, + { url = "https://files.pythonhosted.org/packages/c6/83/713a1e1de8cbbd69af50e26644bbdeef3c1068b89f442417376fa3c0f591/opendal-0.45.20-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:45a3adae1f473052234fc4054a6f210df3ded9aff10db8d545d0a37eff3b13cc", size = 13424302 }, + { url = "https://files.pythonhosted.org/packages/c7/78/c9651e753aaf6eb61887ca372a3f9c2ae57dae03c3159d24deaf018c26dc/opendal-0.45.20-cp311-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:d8947857052c85a4b0e251d50e23f5f68f0cdd9e509e32e614a5e4b2fc7424c4", size = 13622483 }, + { url = "https://files.pythonhosted.org/packages/3c/9d/5d8c20c0fc93df5e349e5694167de30afdc54c5755704cc64764a6cbb309/opendal-0.45.20-cp311-abi3-musllinux_1_1_armv7l.whl", hash = "sha256:891d2f9114efeef648973049ed15e56477e8feb9e48b540bd8d6105ea22a253c", size = 13320229 }, + { url = "https://files.pythonhosted.org/packages/21/39/05262f748a2085522e0c85f03eab945589313dc9caedc002872c39162776/opendal-0.45.20-cp311-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:539de9b825f6783d6289d88c0c9ac5415daa4d892d761e3540c565bda51e8997", size = 14574280 }, + { url = "https://files.pythonhosted.org/packages/74/83/cc7c6de29b0a7585cd445258d174ca204d37729c3874ad08e515b0bf331c/opendal-0.45.20-cp311-abi3-win_amd64.whl", hash = "sha256:145efd56aa33b493d5b652c3e4f5ae5097ab69d38c132d80f108e9f5c1e4d863", size = 14929888 }, ] [[package]] @@ -3739,7 +3708,7 @@ wheels = [ [[package]] name = "opik" -version = "1.7.25" +version = "1.7.29" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "boto3-stubs", extra = ["bedrock-runtime"] }, @@ -3758,9 +3727,9 @@ dependencies = [ { name = "tqdm" }, { name = "uuid6" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/dd/313895410761ee3eb36c1141fa339254c093b3cdfceb79b111c80eb396be/opik-1.7.25.tar.gz", hash = "sha256:5fcdb05bbc98e995f3eea2f94096f98c5ff7a2aca2c895d50636c44d00a07d4b", size = 286950 } +sdist = { url = "https://files.pythonhosted.org/packages/48/94/52faf9277891bfa77dc4bac80b5d88d78103d8fad7f6a6c9495ae083e4da/opik-1.7.29.tar.gz", hash = "sha256:5a13692b233d90663a32cbab452937bf8b6fdc2d516c671c102c3beb34301b64", size = 300856 } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/0a/daee58db3cdd56681672dbc62e5a71200af6d41f34bac2425d1556d3e004/opik-1.7.25-py3-none-any.whl", hash = "sha256:595fc2e6794e35d87449f64dc5d6092705645575d2c34469d04dc2bbe44dd32f", size = 547198 }, + { url = "https://files.pythonhosted.org/packages/2a/43/462b700030c70f525eebf4bc63a226ae46109eca598cd59db081de9a8b21/opik-1.7.29-py3-none-any.whl", hash = "sha256:3eb893e7b612d0b799682060193e4f2eebf55b65811203c4fe46af04cf84fa8c", size = 566635 }, ] [[package]] @@ -3903,15 +3872,15 @@ performance = [ [[package]] name = "pandas-stubs" -version = "2.2.3.250308" +version = "2.2.3.250527" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "types-pytz" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/5a/261f5c67a73e46df2d5984fe7129d66a3ed4864fd7aa9d8721abb3fc802e/pandas_stubs-2.2.3.250308.tar.gz", hash = "sha256:3a6e9daf161f00b85c83772ed3d5cff9522028f07a94817472c07b91f46710fd", size = 103986 } +sdist = { url = "https://files.pythonhosted.org/packages/5f/0d/5fe7f7f3596eb1c2526fea151e9470f86b379183d8b9debe44b2098651ca/pandas_stubs-2.2.3.250527.tar.gz", hash = "sha256:e2d694c4e72106055295ad143664e5c99e5815b07190d1ff85b73b13ff019e63", size = 106312 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/64/ab61d9ca06ff66c07eb804ec27dec1a2be1978b3c3767caaa91e363438cc/pandas_stubs-2.2.3.250308-py3-none-any.whl", hash = "sha256:a377edff3b61f8b268c82499fdbe7c00fdeed13235b8b71d6a1dc347aeddc74d", size = 158053 }, + { url = "https://files.pythonhosted.org/packages/ec/f8/46141ba8c9d7064dc5008bfb4a6ae5bd3c30e4c61c28b5c5ed485bf358ba/pandas_stubs-2.2.3.250527-py3-none-any.whl", hash = "sha256:cd0a49a95b8c5f944e605be711042a4dd8550e2c559b43d70ba2c4b524b66163", size = 159683 }, ] [[package]] @@ -4001,11 +3970,11 @@ wheels = [ [[package]] name = "pluggy" -version = "1.5.0" +version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, ] [[package]] @@ -4057,7 +4026,7 @@ wheels = [ [[package]] name = "posthog" -version = "4.0.1" +version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "backoff" }, @@ -4066,9 +4035,9 @@ dependencies = [ { name = "requests" }, { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cf/6f/835a48728adb60b51dbe6bcc528480e38f1f80769a48704f687d83aefe7e/posthog-4.0.1.tar.gz", hash = "sha256:77e7ebfc6086972db421d3e05c91d5431b2b964865d33a9a32e55dd88da4bff8", size = 78040 } +sdist = { url = "https://files.pythonhosted.org/packages/ce/5b/2e9890700b7b55a370edbfbe5948eae780d48af9b46ad06ea2e7970576f4/posthog-4.2.0.tar.gz", hash = "sha256:c4abc95de03294be005b3b7e8735e9d7abab88583da26262112bacce64b0c3b5", size = 80727 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/f0/8141c04bf105e7fe71b2803fe2193d74a127b447fd149b3e93711ca450c5/posthog-4.0.1-py2.py3-none-any.whl", hash = "sha256:0c76cbab3e5ab0096c4f591c0b536465478357270f926d11ff833c97984659d8", size = 92029 }, + { url = "https://files.pythonhosted.org/packages/51/16/7b6c5844acee2d343d463ee0e3143cd8c7c48a6c0d079a2f7daf0c80b95c/posthog-4.2.0-py2.py3-none-any.whl", hash = "sha256:60c7066caac43e43e326e9196d8c1aadeafc8b0be9e5c108446e352711fa456b", size = 96692 }, ] [[package]] @@ -4138,16 +4107,16 @@ wheels = [ [[package]] name = "protobuf" -version = "4.25.7" +version = "4.25.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/74/63/84fdeac1f03864c2b8b9f0b7fe711c4af5f95759ee281d2026530086b2f5/protobuf-4.25.7.tar.gz", hash = "sha256:28f65ae8c14523cc2c76c1e91680958700d3eac69f45c96512c12c63d9a38807", size = 380612 } +sdist = { url = "https://files.pythonhosted.org/packages/df/01/34c8d2b6354906d728703cb9d546a0e534de479e25f1b581e4094c4a85cc/protobuf-4.25.8.tar.gz", hash = "sha256:6135cf8affe1fc6f76cced2641e4ea8d3e59518d1f24ae41ba97bcad82d397cd", size = 380920 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/ed/9a58076cfb8edc237c92617f1d3744660e9b4457d54f3c2fdf1a4bbae5c7/protobuf-4.25.7-cp310-abi3-win32.whl", hash = "sha256:dc582cf1a73a6b40aa8e7704389b8d8352da616bc8ed5c6cc614bdd0b5ce3f7a", size = 392457 }, - { url = "https://files.pythonhosted.org/packages/28/b3/e00870528029fe252cf3bd6fa535821c276db3753b44a4691aee0d52ff9e/protobuf-4.25.7-cp310-abi3-win_amd64.whl", hash = "sha256:cd873dbddb28460d1706ff4da2e7fac175f62f2a0bebc7b33141f7523c5a2399", size = 413446 }, - { url = "https://files.pythonhosted.org/packages/60/1d/f450a193f875a20099d4492d2c1cb23091d65d512956fb1e167ee61b4bf0/protobuf-4.25.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4c899f09b0502eb39174c717ccf005b844ea93e31137c167ddcacf3e09e49610", size = 394248 }, - { url = "https://files.pythonhosted.org/packages/c8/b8/ea88e9857484a0618c74121618b9e620fc50042de43cdabbebe1b93a83e0/protobuf-4.25.7-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:6d2f5dede3d112e573f0e5f9778c0c19d9f9e209727abecae1d39db789f522c6", size = 293717 }, - { url = "https://files.pythonhosted.org/packages/a7/81/d0b68e9a9a76804113b6dedc6fffed868b97048bbe6f1bedc675bdb8523c/protobuf-4.25.7-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:d41fb7ae72a25fcb79b2d71e4247f0547a02e8185ed51587c22827a87e5736ed", size = 294636 }, - { url = "https://files.pythonhosted.org/packages/17/d7/1e7c80cb2ea2880cfe38580dcfbb22b78b746640c9c13fc3337a6967dc4c/protobuf-4.25.7-py3-none-any.whl", hash = "sha256:e9d969f5154eaeab41404def5dcf04e62162178f4b9de98b2d3c1c70f5f84810", size = 156468 }, + { url = "https://files.pythonhosted.org/packages/45/ff/05f34305fe6b85bbfbecbc559d423a5985605cad5eda4f47eae9e9c9c5c5/protobuf-4.25.8-cp310-abi3-win32.whl", hash = "sha256:504435d831565f7cfac9f0714440028907f1975e4bed228e58e72ecfff58a1e0", size = 392745 }, + { url = "https://files.pythonhosted.org/packages/08/35/8b8a8405c564caf4ba835b1fdf554da869954712b26d8f2a98c0e434469b/protobuf-4.25.8-cp310-abi3-win_amd64.whl", hash = "sha256:bd551eb1fe1d7e92c1af1d75bdfa572eff1ab0e5bf1736716814cdccdb2360f9", size = 413736 }, + { url = "https://files.pythonhosted.org/packages/28/d7/ab27049a035b258dab43445eb6ec84a26277b16105b277cbe0a7698bdc6c/protobuf-4.25.8-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ca809b42f4444f144f2115c4c1a747b9a404d590f18f37e9402422033e464e0f", size = 394537 }, + { url = "https://files.pythonhosted.org/packages/bd/6d/a4a198b61808dd3d1ee187082ccc21499bc949d639feb948961b48be9a7e/protobuf-4.25.8-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:9ad7ef62d92baf5a8654fbb88dac7fa5594cfa70fd3440488a5ca3bfc6d795a7", size = 294005 }, + { url = "https://files.pythonhosted.org/packages/d6/c6/c9deaa6e789b6fc41b88ccbdfe7a42d2b82663248b715f55aa77fbc00724/protobuf-4.25.8-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:83e6e54e93d2b696a92cad6e6efc924f3850f82b52e1563778dfab8b355101b0", size = 294924 }, + { url = "https://files.pythonhosted.org/packages/0c/c1/6aece0ab5209981a70cd186f164c133fdba2f51e124ff92b73de7fd24d78/protobuf-4.25.8-py3-none-any.whl", hash = "sha256:15a0af558aa3b13efef102ae6e4f3efac06f1eea11afb3a57db2901447d9fb59", size = 156757 }, ] [[package]] @@ -4271,7 +4240,7 @@ wheels = [ [[package]] name = "pydantic" -version = "2.11.4" +version = "2.11.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, @@ -4279,9 +4248,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/77/ab/5250d56ad03884ab5efd07f734203943c8a8ab40d551e208af81d0257bf2/pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d", size = 786540 } +sdist = { url = "https://files.pythonhosted.org/packages/f0/86/8ce9040065e8f924d642c58e4a344e33163a07f6b57f836d0d734e0ad3fb/pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a", size = 787102 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/12/46b65f3534d099349e38ef6ec98b1a5a81f42536d17e0ba382c28c67ba67/pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb", size = 443900 }, + { url = "https://files.pythonhosted.org/packages/b5/69/831ed22b38ff9b4b64b66569f0e5b7b97cf3638346eb95a2147fdb49ad5f/pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7", size = 444229 }, ] [[package]] @@ -4334,15 +4303,15 @@ wheels = [ [[package]] name = "pydantic-extra-types" -version = "2.10.4" +version = "2.10.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d9/33/0cde418479949cd6aa1ac669deffcd1c37d8d9cead99ddb48f344e75f2e3/pydantic_extra_types-2.10.4.tar.gz", hash = "sha256:bf8236a63d061eb3ecb1b2afa78ba0f97e3f67aa11dbbff56ec90491e8772edc", size = 95269 } +sdist = { url = "https://files.pythonhosted.org/packages/7e/ba/4178111ec4116c54e1dc7ecd2a1ff8f54256cdbd250e576882911e8f710a/pydantic_extra_types-2.10.5.tar.gz", hash = "sha256:1dcfa2c0cf741a422f088e0dbb4690e7bfadaaf050da3d6f80d6c3cf58a2bad8", size = 138429 } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/ac/bee195ee49256385fad460ce420aeb42703a648dba487c20b6fd107e42ea/pydantic_extra_types-2.10.4-py3-none-any.whl", hash = "sha256:ce064595af3cab05e39ae062752432dcd0362ff80f7e695b61a3493a4d842db7", size = 37276 }, + { url = "https://files.pythonhosted.org/packages/70/1a/5f4fd9e7285f10c44095a4f9fe17d0f358d1702a7c74a9278c794e8a7537/pydantic_extra_types-2.10.5-py3-none-any.whl", hash = "sha256:b60c4e23d573a69a4f1a16dd92888ecc0ef34fb0e655b4f305530377fa70e7a8", size = 38315 }, ] [[package]] @@ -4384,7 +4353,7 @@ crypto = [ [[package]] name = "pymilvus" -version = "2.5.8" +version = "2.5.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "grpcio" }, @@ -4395,9 +4364,9 @@ dependencies = [ { name = "setuptools" }, { name = "ujson" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3b/64/3bc30ab75104a21b9622915b93ffe42f6d250d5d16113624407fcfd42a12/pymilvus-2.5.8.tar.gz", hash = "sha256:48923e7efeebcc366d32b644772796f60484e0ca1a5afc1606d21a10ed98133c", size = 1260355 } +sdist = { url = "https://files.pythonhosted.org/packages/da/e2/88f126a08d8eefba7341e3eb323406a227146094aab7137a2b91d882e98d/pymilvus-2.5.10.tar.gz", hash = "sha256:cc44ad776aeab781ee4c4a4d334b73e746066ab2fb6722c5311f02efa6fc54a2", size = 1260364 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/96/2ce2a0b601d95e373897eb2334f83dba615bd5647b0e4908ff30959920d2/pymilvus-2.5.8-py3-none-any.whl", hash = "sha256:6f33c9e78c041373df6a94724c90ca83448fd231aa33d6298a7a84ed2a5a0236", size = 227647 }, + { url = "https://files.pythonhosted.org/packages/b0/4b/847704930ad8ddd0d0975e9a3a5e3fe704f642debe97454135c2b9ee7081/pymilvus-2.5.10-py3-none-any.whl", hash = "sha256:7da540f93068871cda3941602c55227aeaafb66f2f0d9c05e8f9db783716b100", size = 227635 }, ] [[package]] @@ -4440,18 +4409,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/7d/00cd33c18814bec0a4f6f4a89becdbe2c6c28d78f87d765d0259a22b117e/pyobvector-0.1.20-py3-none-any.whl", hash = "sha256:1a991f8b9f53e1a749fc396ccb90c7591e64b2c5679930023f00789c62e7af72", size = 46264 }, ] -[[package]] -name = "pyopenssl" -version = "24.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c1/d4/1067b82c4fc674d6f6e9e8d26b3dff978da46d351ca3bac171544693e085/pyopenssl-24.3.0.tar.gz", hash = "sha256:49f7a019577d834746bc55c5fce6ecbcec0f2b4ec5ce1cf43a9a173b8138bb36", size = 178944 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/22/40f9162e943f86f0fc927ebc648078be87def360d9d8db346619fb97df2b/pyOpenSSL-24.3.0-py3-none-any.whl", hash = "sha256:e474f5a473cd7f92221cc04976e48f4d11502804657a08a989fb3be5514c904a", size = 56111 }, -] - [[package]] name = "pypandoc" version = "1.15" @@ -4472,11 +4429,11 @@ wheels = [ [[package]] name = "pypdf" -version = "5.5.0" +version = "5.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/c8/543f8ae1cd9e182e9f979d9ab1df18e3445350471abadbdabc0166ae5741/pypdf-5.5.0.tar.gz", hash = "sha256:8ce6a18389f7394fd09a1d4b7a34b097b11c19088a23cfd09e5008f85893e254", size = 5021690 } +sdist = { url = "https://files.pythonhosted.org/packages/40/46/67de1d7a65412aa1c896e6b280829b70b57d203fadae6859b690006b8e0a/pypdf-5.6.0.tar.gz", hash = "sha256:a4b6538b77fc796622000db7127e4e58039ec5e6afd292f8e9bf42e2e985a749", size = 5023749 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/4e/931b90b51e3ebc69699be926b3d5bfdabae2d9c84337fd0c9fb98adbf70c/pypdf-5.5.0-py3-none-any.whl", hash = "sha256:2f61f2d32dde00471cd70b8977f98960c64e84dd5ba0d070e953fcb4da0b2a73", size = 303371 }, + { url = "https://files.pythonhosted.org/packages/71/8b/dc3a72d98c22be7a4cbd664ad14c5a3e6295c2dbdf572865ed61e24b5e38/pypdf-5.6.0-py3-none-any.whl", hash = "sha256:ca6bf446bfb0a2d8d71d6d6bb860798d864c36a29b3d9ae8d7fc7958c59f88e7", size = 304208 }, ] [[package]] @@ -4578,14 +4535,14 @@ wheels = [ [[package]] name = "pytest-mock" -version = "3.14.0" +version = "3.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 } +sdist = { url = "https://files.pythonhosted.org/packages/71/28/67172c96ba684058a4d24ffe144d64783d2a270d0af0d9e792737bddc75c/pytest_mock-3.14.1.tar.gz", hash = "sha256:159e9edac4c451ce77a5cdb9fc5d1100708d2dd4ba3c3df572f14097351af80e", size = 33241 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863 }, + { url = "https://files.pythonhosted.org/packages/b2/05/77b60e520511c53d1c1ca75f1930c7dd8e971d0c4379b7f4b3f9644685ba/pytest_mock-3.14.1-py3-none-any.whl", hash = "sha256:178aefcd11307d874b4cd3100344e7e2d888d9791a6a1d9bfe90fbc1b74fd1d0", size = 9923 }, ] [[package]] @@ -4842,7 +4799,7 @@ wheels = [ [[package]] name = "realtime" -version = "2.4.3" +version = "2.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -4850,21 +4807,21 @@ dependencies = [ { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/75/fc/ef69bd4a1bf30a5435bc2d09f6c33bfef5f317746b1a4ca2932ef14b22fc/realtime-2.4.3.tar.gz", hash = "sha256:152febabc822ce60e11f202842c5aa6858ae4bd04920bfd6a00c1dd492f426b0", size = 18849 } +sdist = { url = "https://files.pythonhosted.org/packages/47/9e/d6e478ccc23869a450a5d0dd9ab0c8a4e37fee7aec43c925d89bb09fcaf5/realtime-2.5.0.tar.gz", hash = "sha256:03d744dedc823de019a7f9917c1a6509fb6e98d357adf7fd7f4015618dac7ecd", size = 18865 } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/0c/68ce3db6354c466f68bba2be0fe0ad3a93dca8219e10b9bad3138077efec/realtime-2.4.3-py3-none-any.whl", hash = "sha256:09ff3b61ac928413a27765640b67362380eaddba84a7037a17972a64b1ac52f7", size = 22086 }, + { url = "https://files.pythonhosted.org/packages/52/09/a9ede9afa4a536ac84ad365bfa26116ab17463c8353f471b2396dc0e44d0/realtime-2.5.0-py3-none-any.whl", hash = "sha256:a54274a6cdc03c3eda61fbfec1d277e4a28e3aa9526d24b5c187385bb8a7e85a", size = 22086 }, ] [[package]] name = "redis" -version = "6.1.0" +version = "6.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "async-timeout", marker = "python_full_version < '3.11.3'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/af/e875d57383653e5d9065df8552de1deb7576b4d3cf3af90cde2e79ff7f65/redis-6.1.0.tar.gz", hash = "sha256:c928e267ad69d3069af28a9823a07726edf72c7e37764f43dc0123f37928c075", size = 4629300 } +sdist = { url = "https://files.pythonhosted.org/packages/07/8b/14ef373ffe71c0d2fde93c204eab78472ea13c021d9aee63b0e11bd65896/redis-6.1.1.tar.gz", hash = "sha256:88c689325b5b41cedcbdbdfd4d937ea86cf6dab2222a83e86d8a466e4b3d2600", size = 4629515 } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/5f/cf36360f80ae233bd1836442f5127818cfcfc7b1846179b60b2e9a4c45c9/redis-6.1.0-py3-none-any.whl", hash = "sha256:3b72622f3d3a89df2a6041e82acd896b0e67d9f54e9bcd906d091d23ba5219f6", size = 273750 }, + { url = "https://files.pythonhosted.org/packages/c2/cd/29503c609186104c363ef1f38d6e752e7d91ef387fc90aa165e96d69f446/redis-6.1.1-py3-none-any.whl", hash = "sha256:ed44d53d065bbe04ac6d76864e331cfe5c5353f86f6deccc095f8794fd15bb2e", size = 273930 }, ] [package.optional-dependencies] @@ -5005,47 +4962,49 @@ wheels = [ [[package]] name = "rpds-py" -version = "0.24.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/b3/52b213298a0ba7097c7ea96bee95e1947aa84cc816d48cebb539770cdf41/rpds_py-0.24.0.tar.gz", hash = "sha256:772cc1b2cd963e7e17e6cc55fe0371fb9c704d63e44cacec7b9b7f523b78919e", size = 26863 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/80/e6/c1458bbfb257448fdb2528071f1f4e19e26798ed5ef6d47d7aab0cb69661/rpds_py-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2d3ee4615df36ab8eb16c2507b11e764dcc11fd350bbf4da16d09cda11fcedef", size = 377679 }, - { url = "https://files.pythonhosted.org/packages/dd/26/ea4181ef78f58b2c167548c6a833d7dc22408e5b3b181bda9dda440bb92d/rpds_py-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e13ae74a8a3a0c2f22f450f773e35f893484fcfacb00bb4344a7e0f4f48e1f97", size = 362571 }, - { url = "https://files.pythonhosted.org/packages/56/fa/1ec54dd492c64c280a2249a047fc3369e2789dc474eac20445ebfc72934b/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf86f72d705fc2ef776bb7dd9e5fbba79d7e1f3e258bf9377f8204ad0fc1c51e", size = 388012 }, - { url = "https://files.pythonhosted.org/packages/3a/be/bad8b0e0f7e58ef4973bb75e91c472a7d51da1977ed43b09989264bf065c/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c43583ea8517ed2e780a345dd9960896afc1327e8cf3ac8239c167530397440d", size = 394730 }, - { url = "https://files.pythonhosted.org/packages/35/56/ab417fc90c21826df048fc16e55316ac40876e4b790104ececcbce813d8f/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cd031e63bc5f05bdcda120646a0d32f6d729486d0067f09d79c8db5368f4586", size = 448264 }, - { url = "https://files.pythonhosted.org/packages/b6/75/4c63862d5c05408589196c8440a35a14ea4ae337fa70ded1f03638373f06/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34d90ad8c045df9a4259c47d2e16a3f21fdb396665c94520dbfe8766e62187a4", size = 446813 }, - { url = "https://files.pythonhosted.org/packages/e7/0c/91cf17dffa9a38835869797a9f041056091ebba6a53963d3641207e3d467/rpds_py-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e838bf2bb0b91ee67bf2b889a1a841e5ecac06dd7a2b1ef4e6151e2ce155c7ae", size = 389438 }, - { url = "https://files.pythonhosted.org/packages/1b/b0/60e6c72727c978276e02851819f3986bc40668f115be72c1bc4d922c950f/rpds_py-0.24.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04ecf5c1ff4d589987b4d9882872f80ba13da7d42427234fce8f22efb43133bc", size = 420416 }, - { url = "https://files.pythonhosted.org/packages/a1/d7/f46f85b9f863fb59fd3c534b5c874c48bee86b19e93423b9da8784605415/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:630d3d8ea77eabd6cbcd2ea712e1c5cecb5b558d39547ac988351195db433f6c", size = 565236 }, - { url = "https://files.pythonhosted.org/packages/2a/d1/1467620ded6dd70afc45ec822cdf8dfe7139537780d1f3905de143deb6fd/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ebcb786b9ff30b994d5969213a8430cbb984cdd7ea9fd6df06663194bd3c450c", size = 592016 }, - { url = "https://files.pythonhosted.org/packages/5d/13/fb1ded2e6adfaa0c0833106c42feb290973f665300f4facd5bf5d7891d9c/rpds_py-0.24.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:174e46569968ddbbeb8a806d9922f17cd2b524aa753b468f35b97ff9c19cb718", size = 560123 }, - { url = "https://files.pythonhosted.org/packages/1e/df/09fc1857ac7cc2eb16465a7199c314cbce7edde53c8ef21d615410d7335b/rpds_py-0.24.0-cp311-cp311-win32.whl", hash = "sha256:5ef877fa3bbfb40b388a5ae1cb00636a624690dcb9a29a65267054c9ea86d88a", size = 222256 }, - { url = "https://files.pythonhosted.org/packages/ff/25/939b40bc4d54bf910e5ee60fb5af99262c92458f4948239e8c06b0b750e7/rpds_py-0.24.0-cp311-cp311-win_amd64.whl", hash = "sha256:e274f62cbd274359eff63e5c7e7274c913e8e09620f6a57aae66744b3df046d6", size = 234718 }, - { url = "https://files.pythonhosted.org/packages/1a/e0/1c55f4a3be5f1ca1a4fd1f3ff1504a1478c1ed48d84de24574c4fa87e921/rpds_py-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d8551e733626afec514b5d15befabea0dd70a343a9f23322860c4f16a9430205", size = 366945 }, - { url = "https://files.pythonhosted.org/packages/39/1b/a3501574fbf29118164314dbc800d568b8c1c7b3258b505360e8abb3902c/rpds_py-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e374c0ce0ca82e5b67cd61fb964077d40ec177dd2c4eda67dba130de09085c7", size = 351935 }, - { url = "https://files.pythonhosted.org/packages/dc/47/77d3d71c55f6a374edde29f1aca0b2e547325ed00a9da820cabbc9497d2b/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d69d003296df4840bd445a5d15fa5b6ff6ac40496f956a221c4d1f6f7b4bc4d9", size = 390817 }, - { url = "https://files.pythonhosted.org/packages/4e/ec/1e336ee27484379e19c7f9cc170f4217c608aee406d3ae3a2e45336bff36/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8212ff58ac6dfde49946bea57474a386cca3f7706fc72c25b772b9ca4af6b79e", size = 401983 }, - { url = "https://files.pythonhosted.org/packages/07/f8/39b65cbc272c635eaea6d393c2ad1ccc81c39eca2db6723a0ca4b2108fce/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:528927e63a70b4d5f3f5ccc1fa988a35456eb5d15f804d276709c33fc2f19bda", size = 451719 }, - { url = "https://files.pythonhosted.org/packages/32/05/05c2b27dd9c30432f31738afed0300659cb9415db0ff7429b05dfb09bbde/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a824d2c7a703ba6daaca848f9c3d5cb93af0505be505de70e7e66829affd676e", size = 442546 }, - { url = "https://files.pythonhosted.org/packages/7d/e0/19383c8b5d509bd741532a47821c3e96acf4543d0832beba41b4434bcc49/rpds_py-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44d51febb7a114293ffd56c6cf4736cb31cd68c0fddd6aa303ed09ea5a48e029", size = 393695 }, - { url = "https://files.pythonhosted.org/packages/9d/15/39f14e96d94981d0275715ae8ea564772237f3fa89bc3c21e24de934f2c7/rpds_py-0.24.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3fab5f4a2c64a8fb64fc13b3d139848817a64d467dd6ed60dcdd6b479e7febc9", size = 427218 }, - { url = "https://files.pythonhosted.org/packages/22/b9/12da7124905a680f690da7a9de6f11de770b5e359f5649972f7181c8bf51/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9be4f99bee42ac107870c61dfdb294d912bf81c3c6d45538aad7aecab468b6b7", size = 568062 }, - { url = "https://files.pythonhosted.org/packages/88/17/75229017a2143d915f6f803721a6d721eca24f2659c5718a538afa276b4f/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:564c96b6076a98215af52f55efa90d8419cc2ef45d99e314fddefe816bc24f91", size = 596262 }, - { url = "https://files.pythonhosted.org/packages/aa/64/8e8a1d8bd1b6b638d6acb6d41ab2cec7f2067a5b8b4c9175703875159a7c/rpds_py-0.24.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:75a810b7664c17f24bf2ffd7f92416c00ec84b49bb68e6a0d93e542406336b56", size = 564306 }, - { url = "https://files.pythonhosted.org/packages/68/1c/a7eac8d8ed8cb234a9b1064647824c387753343c3fab6ed7c83481ed0be7/rpds_py-0.24.0-cp312-cp312-win32.whl", hash = "sha256:f6016bd950be4dcd047b7475fdf55fb1e1f59fc7403f387be0e8123e4a576d30", size = 224281 }, - { url = "https://files.pythonhosted.org/packages/bb/46/b8b5424d1d21f2f2f3f2d468660085318d4f74a8df8289e3dd6ad224d488/rpds_py-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:998c01b8e71cf051c28f5d6f1187abbdf5cf45fc0efce5da6c06447cba997034", size = 239719 }, - { url = "https://files.pythonhosted.org/packages/65/53/40bcc246a8354530d51a26d2b5b9afd1deacfb0d79e67295cc74df362f52/rpds_py-0.24.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f9e0057a509e096e47c87f753136c9b10d7a91842d8042c2ee6866899a717c0d", size = 378386 }, - { url = "https://files.pythonhosted.org/packages/80/b0/5ea97dd2f53e3618560aa1f9674e896e63dff95a9b796879a201bc4c1f00/rpds_py-0.24.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6e109a454412ab82979c5b1b3aee0604eca4bbf9a02693bb9df027af2bfa91a", size = 363440 }, - { url = "https://files.pythonhosted.org/packages/57/9d/259b6eada6f747cdd60c9a5eb3efab15f6704c182547149926c38e5bd0d5/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc1c892b1ec1f8cbd5da8de287577b455e388d9c328ad592eabbdcb6fc93bee5", size = 388816 }, - { url = "https://files.pythonhosted.org/packages/94/c1/faafc7183712f89f4b7620c3c15979ada13df137d35ef3011ae83e93b005/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c39438c55983d48f4bb3487734d040e22dad200dab22c41e331cee145e7a50d", size = 395058 }, - { url = "https://files.pythonhosted.org/packages/6c/96/d7fa9d2a7b7604a61da201cc0306a355006254942093779d7121c64700ce/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d7e8ce990ae17dda686f7e82fd41a055c668e13ddcf058e7fb5e9da20b57793", size = 448692 }, - { url = "https://files.pythonhosted.org/packages/96/37/a3146c6eebc65d6d8c96cc5ffdcdb6af2987412c789004213227fbe52467/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ea7f4174d2e4194289cb0c4e172d83e79a6404297ff95f2875cf9ac9bced8ba", size = 446462 }, - { url = "https://files.pythonhosted.org/packages/1f/13/6481dfd9ac7de43acdaaa416e3a7da40bc4bb8f5c6ca85e794100aa54596/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb2954155bb8f63bb19d56d80e5e5320b61d71084617ed89efedb861a684baea", size = 390460 }, - { url = "https://files.pythonhosted.org/packages/61/e1/37e36bce65e109543cc4ff8d23206908649023549604fa2e7fbeba5342f7/rpds_py-0.24.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04f2b712a2206e13800a8136b07aaedc23af3facab84918e7aa89e4be0260032", size = 421609 }, - { url = "https://files.pythonhosted.org/packages/20/dd/1f1a923d6cd798b8582176aca8a0784676f1a0449fb6f07fce6ac1cdbfb6/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:eda5c1e2a715a4cbbca2d6d304988460942551e4e5e3b7457b50943cd741626d", size = 565818 }, - { url = "https://files.pythonhosted.org/packages/56/ec/d8da6df6a1eb3a418944a17b1cb38dd430b9e5a2e972eafd2b06f10c7c46/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:9abc80fe8c1f87218db116016de575a7998ab1629078c90840e8d11ab423ee25", size = 592627 }, - { url = "https://files.pythonhosted.org/packages/b3/14/c492b9c7d5dd133e13f211ddea6bb9870f99e4f73932f11aa00bc09a9be9/rpds_py-0.24.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6a727fd083009bc83eb83d6950f0c32b3c94c8b80a9b667c87f4bd1274ca30ba", size = 560885 }, +version = "0.25.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/a6/60184b7fc00dd3ca80ac635dd5b8577d444c57e8e8742cecabfacb829921/rpds_py-0.25.1.tar.gz", hash = "sha256:8960b6dac09b62dac26e75d7e2c4a22efb835d827a7278c34f72b2b84fa160e3", size = 27304 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/e1/df13fe3ddbbea43567e07437f097863b20c99318ae1f58a0fe389f763738/rpds_py-0.25.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5f048bbf18b1f9120685c6d6bb70cc1a52c8cc11bdd04e643d28d3be0baf666d", size = 373341 }, + { url = "https://files.pythonhosted.org/packages/7a/58/deef4d30fcbcbfef3b6d82d17c64490d5c94585a2310544ce8e2d3024f83/rpds_py-0.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fbb0dbba559959fcb5d0735a0f87cdbca9e95dac87982e9b95c0f8f7ad10255", size = 359111 }, + { url = "https://files.pythonhosted.org/packages/bb/7e/39f1f4431b03e96ebaf159e29a0f82a77259d8f38b2dd474721eb3a8ac9b/rpds_py-0.25.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4ca54b9cf9d80b4016a67a0193ebe0bcf29f6b0a96f09db942087e294d3d4c2", size = 386112 }, + { url = "https://files.pythonhosted.org/packages/db/e7/847068a48d63aec2ae695a1646089620b3b03f8ccf9f02c122ebaf778f3c/rpds_py-0.25.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ee3e26eb83d39b886d2cb6e06ea701bba82ef30a0de044d34626ede51ec98b0", size = 400362 }, + { url = "https://files.pythonhosted.org/packages/3b/3d/9441d5db4343d0cee759a7ab4d67420a476cebb032081763de934719727b/rpds_py-0.25.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89706d0683c73a26f76a5315d893c051324d771196ae8b13e6ffa1ffaf5e574f", size = 522214 }, + { url = "https://files.pythonhosted.org/packages/a2/ec/2cc5b30d95f9f1a432c79c7a2f65d85e52812a8f6cbf8768724571710786/rpds_py-0.25.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2013ee878c76269c7b557a9a9c042335d732e89d482606990b70a839635feb7", size = 411491 }, + { url = "https://files.pythonhosted.org/packages/dc/6c/44695c1f035077a017dd472b6a3253553780837af2fac9b6ac25f6a5cb4d/rpds_py-0.25.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45e484db65e5380804afbec784522de84fa95e6bb92ef1bd3325d33d13efaebd", size = 386978 }, + { url = "https://files.pythonhosted.org/packages/b1/74/b4357090bb1096db5392157b4e7ed8bb2417dc7799200fcbaee633a032c9/rpds_py-0.25.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:48d64155d02127c249695abb87d39f0faf410733428d499867606be138161d65", size = 420662 }, + { url = "https://files.pythonhosted.org/packages/26/dd/8cadbebf47b96e59dfe8b35868e5c38a42272699324e95ed522da09d3a40/rpds_py-0.25.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:048893e902132fd6548a2e661fb38bf4896a89eea95ac5816cf443524a85556f", size = 563385 }, + { url = "https://files.pythonhosted.org/packages/c3/ea/92960bb7f0e7a57a5ab233662f12152085c7dc0d5468534c65991a3d48c9/rpds_py-0.25.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0317177b1e8691ab5879f4f33f4b6dc55ad3b344399e23df2e499de7b10a548d", size = 592047 }, + { url = "https://files.pythonhosted.org/packages/61/ad/71aabc93df0d05dabcb4b0c749277881f8e74548582d96aa1bf24379493a/rpds_py-0.25.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bffcf57826d77a4151962bf1701374e0fc87f536e56ec46f1abdd6a903354042", size = 557863 }, + { url = "https://files.pythonhosted.org/packages/93/0f/89df0067c41f122b90b76f3660028a466eb287cbe38efec3ea70e637ca78/rpds_py-0.25.1-cp311-cp311-win32.whl", hash = "sha256:cda776f1967cb304816173b30994faaf2fd5bcb37e73118a47964a02c348e1bc", size = 219627 }, + { url = "https://files.pythonhosted.org/packages/7c/8d/93b1a4c1baa903d0229374d9e7aa3466d751f1d65e268c52e6039c6e338e/rpds_py-0.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:dc3c1ff0abc91444cd20ec643d0f805df9a3661fcacf9c95000329f3ddf268a4", size = 231603 }, + { url = "https://files.pythonhosted.org/packages/cb/11/392605e5247bead2f23e6888e77229fbd714ac241ebbebb39a1e822c8815/rpds_py-0.25.1-cp311-cp311-win_arm64.whl", hash = "sha256:5a3ddb74b0985c4387719fc536faced33cadf2172769540c62e2a94b7b9be1c4", size = 223967 }, + { url = "https://files.pythonhosted.org/packages/7f/81/28ab0408391b1dc57393653b6a0cf2014cc282cc2909e4615e63e58262be/rpds_py-0.25.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5ffe453cde61f73fea9430223c81d29e2fbf412a6073951102146c84e19e34c", size = 364647 }, + { url = "https://files.pythonhosted.org/packages/2c/9a/7797f04cad0d5e56310e1238434f71fc6939d0bc517192a18bb99a72a95f/rpds_py-0.25.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:115874ae5e2fdcfc16b2aedc95b5eef4aebe91b28e7e21951eda8a5dc0d3461b", size = 350454 }, + { url = "https://files.pythonhosted.org/packages/69/3c/93d2ef941b04898011e5d6eaa56a1acf46a3b4c9f4b3ad1bbcbafa0bee1f/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a714bf6e5e81b0e570d01f56e0c89c6375101b8463999ead3a93a5d2a4af91fa", size = 389665 }, + { url = "https://files.pythonhosted.org/packages/c1/57/ad0e31e928751dde8903a11102559628d24173428a0f85e25e187defb2c1/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35634369325906bcd01577da4c19e3b9541a15e99f31e91a02d010816b49bfda", size = 403873 }, + { url = "https://files.pythonhosted.org/packages/16/ad/c0c652fa9bba778b4f54980a02962748479dc09632e1fd34e5282cf2556c/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4cb2b3ddc16710548801c6fcc0cfcdeeff9dafbc983f77265877793f2660309", size = 525866 }, + { url = "https://files.pythonhosted.org/packages/2a/39/3e1839bc527e6fcf48d5fec4770070f872cdee6c6fbc9b259932f4e88a38/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ceca1cf097ed77e1a51f1dbc8d174d10cb5931c188a4505ff9f3e119dfe519b", size = 416886 }, + { url = "https://files.pythonhosted.org/packages/7a/95/dd6b91cd4560da41df9d7030a038298a67d24f8ca38e150562644c829c48/rpds_py-0.25.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2cd1a4b0c2b8c5e31ffff50d09f39906fe351389ba143c195566056c13a7ea", size = 390666 }, + { url = "https://files.pythonhosted.org/packages/64/48/1be88a820e7494ce0a15c2d390ccb7c52212370badabf128e6a7bb4cb802/rpds_py-0.25.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de336a4b164c9188cb23f3703adb74a7623ab32d20090d0e9bf499a2203ad65", size = 425109 }, + { url = "https://files.pythonhosted.org/packages/cf/07/3e2a17927ef6d7720b9949ec1b37d1e963b829ad0387f7af18d923d5cfa5/rpds_py-0.25.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9fca84a15333e925dd59ce01da0ffe2ffe0d6e5d29a9eeba2148916d1824948c", size = 567244 }, + { url = "https://files.pythonhosted.org/packages/d2/e5/76cf010998deccc4f95305d827847e2eae9c568099c06b405cf96384762b/rpds_py-0.25.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88ec04afe0c59fa64e2f6ea0dd9657e04fc83e38de90f6de201954b4d4eb59bd", size = 596023 }, + { url = "https://files.pythonhosted.org/packages/52/9a/df55efd84403736ba37a5a6377b70aad0fd1cb469a9109ee8a1e21299a1c/rpds_py-0.25.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8bd2f19e312ce3e1d2c635618e8a8d8132892bb746a7cf74780a489f0f6cdcb", size = 561634 }, + { url = "https://files.pythonhosted.org/packages/ab/aa/dc3620dd8db84454aaf9374bd318f1aa02578bba5e567f5bf6b79492aca4/rpds_py-0.25.1-cp312-cp312-win32.whl", hash = "sha256:e5e2f7280d8d0d3ef06f3ec1b4fd598d386cc6f0721e54f09109a8132182fbfe", size = 222713 }, + { url = "https://files.pythonhosted.org/packages/a3/7f/7cef485269a50ed5b4e9bae145f512d2a111ca638ae70cc101f661b4defd/rpds_py-0.25.1-cp312-cp312-win_amd64.whl", hash = "sha256:db58483f71c5db67d643857404da360dce3573031586034b7d59f245144cc192", size = 235280 }, + { url = "https://files.pythonhosted.org/packages/99/f2/c2d64f6564f32af913bf5f3f7ae41c7c263c5ae4c4e8f1a17af8af66cd46/rpds_py-0.25.1-cp312-cp312-win_arm64.whl", hash = "sha256:6d50841c425d16faf3206ddbba44c21aa3310a0cebc3c1cdfc3e3f4f9f6f5728", size = 225399 }, + { url = "https://files.pythonhosted.org/packages/49/74/48f3df0715a585cbf5d34919c9c757a4c92c1a9eba059f2d334e72471f70/rpds_py-0.25.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee86d81551ec68a5c25373c5643d343150cc54672b5e9a0cafc93c1870a53954", size = 374208 }, + { url = "https://files.pythonhosted.org/packages/55/b0/9b01bb11ce01ec03d05e627249cc2c06039d6aa24ea5a22a39c312167c10/rpds_py-0.25.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89c24300cd4a8e4a51e55c31a8ff3918e6651b241ee8876a42cc2b2a078533ba", size = 359262 }, + { url = "https://files.pythonhosted.org/packages/a9/eb/5395621618f723ebd5116c53282052943a726dba111b49cd2071f785b665/rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:771c16060ff4e79584dc48902a91ba79fd93eade3aa3a12d6d2a4aadaf7d542b", size = 387366 }, + { url = "https://files.pythonhosted.org/packages/68/73/3d51442bdb246db619d75039a50ea1cf8b5b4ee250c3e5cd5c3af5981cd4/rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:785ffacd0ee61c3e60bdfde93baa6d7c10d86f15655bd706c89da08068dc5038", size = 400759 }, + { url = "https://files.pythonhosted.org/packages/b7/4c/3a32d5955d7e6cb117314597bc0f2224efc798428318b13073efe306512a/rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a40046a529cc15cef88ac5ab589f83f739e2d332cb4d7399072242400ed68c9", size = 523128 }, + { url = "https://files.pythonhosted.org/packages/be/95/1ffccd3b0bb901ae60b1dd4b1be2ab98bb4eb834cd9b15199888f5702f7b/rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85fc223d9c76cabe5d0bff82214459189720dc135db45f9f66aa7cffbf9ff6c1", size = 411597 }, + { url = "https://files.pythonhosted.org/packages/ef/6d/6e6cd310180689db8b0d2de7f7d1eabf3fb013f239e156ae0d5a1a85c27f/rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0be9965f93c222fb9b4cc254235b3b2b215796c03ef5ee64f995b1b69af0762", size = 388053 }, + { url = "https://files.pythonhosted.org/packages/4a/87/ec4186b1fe6365ced6fa470960e68fc7804bafbe7c0cf5a36237aa240efa/rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8378fa4a940f3fb509c081e06cb7f7f2adae8cf46ef258b0e0ed7519facd573e", size = 421821 }, + { url = "https://files.pythonhosted.org/packages/7a/60/84f821f6bf4e0e710acc5039d91f8f594fae0d93fc368704920d8971680d/rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:33358883a4490287e67a2c391dfaea4d9359860281db3292b6886bf0be3d8692", size = 564534 }, + { url = "https://files.pythonhosted.org/packages/41/3a/bc654eb15d3b38f9330fe0f545016ba154d89cdabc6177b0295910cd0ebe/rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1d1fadd539298e70cac2f2cb36f5b8a65f742b9b9f1014dd4ea1f7785e2470bf", size = 592674 }, + { url = "https://files.pythonhosted.org/packages/2e/ba/31239736f29e4dfc7a58a45955c5db852864c306131fd6320aea214d5437/rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a46c2fb2545e21181445515960006e85d22025bd2fe6db23e76daec6eb689fe", size = 558781 }, ] [[package]] @@ -5062,27 +5021,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.11.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/e7/e55dda1c92cdcf34b677ebef17486669800de01e887b7831a1b8fdf5cb08/ruff-0.11.9.tar.gz", hash = "sha256:ebd58d4f67a00afb3a30bf7d383e52d0e036e6195143c6db7019604a05335517", size = 4132134 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/71/75dfb7194fe6502708e547941d41162574d1f579c4676a8eb645bf1a6842/ruff-0.11.9-py3-none-linux_armv6l.whl", hash = "sha256:a31a1d143a5e6f499d1fb480f8e1e780b4dfdd580f86e05e87b835d22c5c6f8c", size = 10335453 }, - { url = "https://files.pythonhosted.org/packages/74/fc/ad80c869b1732f53c4232bbf341f33c5075b2c0fb3e488983eb55964076a/ruff-0.11.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:66bc18ca783b97186a1f3100e91e492615767ae0a3be584e1266aa9051990722", size = 11072566 }, - { url = "https://files.pythonhosted.org/packages/87/0d/0ccececef8a0671dae155cbf7a1f90ea2dd1dba61405da60228bbe731d35/ruff-0.11.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bd576cd06962825de8aece49f28707662ada6a1ff2db848d1348e12c580acbf1", size = 10435020 }, - { url = "https://files.pythonhosted.org/packages/52/01/e249e1da6ad722278094e183cbf22379a9bbe5f21a3e46cef24ccab76e22/ruff-0.11.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b1d18b4be8182cc6fddf859ce432cc9631556e9f371ada52f3eaefc10d878de", size = 10593935 }, - { url = "https://files.pythonhosted.org/packages/ed/9a/40cf91f61e3003fe7bd43f1761882740e954506c5a0f9097b1cff861f04c/ruff-0.11.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0f3f46f759ac623e94824b1e5a687a0df5cd7f5b00718ff9c24f0a894a683be7", size = 10172971 }, - { url = "https://files.pythonhosted.org/packages/61/12/d395203de1e8717d7a2071b5a340422726d4736f44daf2290aad1085075f/ruff-0.11.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f34847eea11932d97b521450cf3e1d17863cfa5a94f21a056b93fb86f3f3dba2", size = 11748631 }, - { url = "https://files.pythonhosted.org/packages/66/d6/ef4d5eba77677eab511644c37c55a3bb8dcac1cdeb331123fe342c9a16c9/ruff-0.11.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f33b15e00435773df97cddcd263578aa83af996b913721d86f47f4e0ee0ff271", size = 12409236 }, - { url = "https://files.pythonhosted.org/packages/c5/8f/5a2c5fc6124dd925a5faf90e1089ee9036462118b619068e5b65f8ea03df/ruff-0.11.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7b27613a683b086f2aca8996f63cb3dd7bc49e6eccf590563221f7b43ded3f65", size = 11881436 }, - { url = "https://files.pythonhosted.org/packages/39/d1/9683f469ae0b99b95ef99a56cfe8c8373c14eba26bd5c622150959ce9f64/ruff-0.11.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e0d88756e63e8302e630cee3ce2ffb77859797cc84a830a24473939e6da3ca6", size = 13982759 }, - { url = "https://files.pythonhosted.org/packages/4e/0b/c53a664f06e0faab596397867c6320c3816df479e888fe3af63bc3f89699/ruff-0.11.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:537c82c9829d7811e3aa680205f94c81a2958a122ac391c0eb60336ace741a70", size = 11541985 }, - { url = "https://files.pythonhosted.org/packages/23/a0/156c4d7e685f6526a636a60986ee4a3c09c8c4e2a49b9a08c9913f46c139/ruff-0.11.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:440ac6a7029f3dee7d46ab7de6f54b19e34c2b090bb4f2480d0a2d635228f381", size = 10465775 }, - { url = "https://files.pythonhosted.org/packages/43/d5/88b9a6534d9d4952c355e38eabc343df812f168a2c811dbce7d681aeb404/ruff-0.11.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:71c539bac63d0788a30227ed4d43b81353c89437d355fdc52e0cda4ce5651787", size = 10170957 }, - { url = "https://files.pythonhosted.org/packages/f0/b8/2bd533bdaf469dc84b45815ab806784d561fab104d993a54e1852596d581/ruff-0.11.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c67117bc82457e4501473c5f5217d49d9222a360794bfb63968e09e70f340abd", size = 11143307 }, - { url = "https://files.pythonhosted.org/packages/2f/d9/43cfba291788459b9bfd4e09a0479aa94d05ab5021d381a502d61a807ec1/ruff-0.11.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e4b78454f97aa454586e8a5557facb40d683e74246c97372af3c2d76901d697b", size = 11603026 }, - { url = "https://files.pythonhosted.org/packages/22/e6/7ed70048e89b01d728ccc950557a17ecf8df4127b08a56944b9d0bae61bc/ruff-0.11.9-py3-none-win32.whl", hash = "sha256:7fe1bc950e7d7b42caaee2a8a3bc27410547cc032c9558ee2e0f6d3b209e845a", size = 10548627 }, - { url = "https://files.pythonhosted.org/packages/90/36/1da5d566271682ed10f436f732e5f75f926c17255c9c75cefb77d4bf8f10/ruff-0.11.9-py3-none-win_amd64.whl", hash = "sha256:52edaa4a6d70f8180343a5b7f030c7edd36ad180c9f4d224959c2d689962d964", size = 11634340 }, - { url = "https://files.pythonhosted.org/packages/40/f7/70aad26e5877c8f7ee5b161c4c9fa0100e63fc4c944dc6d97b9c7e871417/ruff-0.11.9-py3-none-win_arm64.whl", hash = "sha256:bcf42689c22f2e240f496d0c183ef2c6f7b35e809f12c1db58f75d9aa8d630ca", size = 10741080 }, +version = "0.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/0a/92416b159ec00cdf11e5882a9d80d29bf84bba3dbebc51c4898bfbca1da6/ruff-0.11.12.tar.gz", hash = "sha256:43cf7f69c7d7c7d7513b9d59c5d8cafd704e05944f978614aa9faff6ac202603", size = 4202289 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/cc/53eb79f012d15e136d40a8e8fc519ba8f55a057f60b29c2df34efd47c6e3/ruff-0.11.12-py3-none-linux_armv6l.whl", hash = "sha256:c7680aa2f0d4c4f43353d1e72123955c7a2159b8646cd43402de6d4a3a25d7cc", size = 10285597 }, + { url = "https://files.pythonhosted.org/packages/e7/d7/73386e9fb0232b015a23f62fea7503f96e29c29e6c45461d4a73bac74df9/ruff-0.11.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:2cad64843da9f134565c20bcc430642de897b8ea02e2e79e6e02a76b8dcad7c3", size = 11053154 }, + { url = "https://files.pythonhosted.org/packages/4e/eb/3eae144c5114e92deb65a0cb2c72326c8469e14991e9bc3ec0349da1331c/ruff-0.11.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9b6886b524a1c659cee1758140138455d3c029783d1b9e643f3624a5ee0cb0aa", size = 10403048 }, + { url = "https://files.pythonhosted.org/packages/29/64/20c54b20e58b1058db6689e94731f2a22e9f7abab74e1a758dfba058b6ca/ruff-0.11.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc3a3690aad6e86c1958d3ec3c38c4594b6ecec75c1f531e84160bd827b2012", size = 10597062 }, + { url = "https://files.pythonhosted.org/packages/29/3a/79fa6a9a39422a400564ca7233a689a151f1039110f0bbbabcb38106883a/ruff-0.11.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f97fdbc2549f456c65b3b0048560d44ddd540db1f27c778a938371424b49fe4a", size = 10155152 }, + { url = "https://files.pythonhosted.org/packages/e5/a4/22c2c97b2340aa968af3a39bc38045e78d36abd4ed3fa2bde91c31e712e3/ruff-0.11.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74adf84960236961090e2d1348c1a67d940fd12e811a33fb3d107df61eef8fc7", size = 11723067 }, + { url = "https://files.pythonhosted.org/packages/bc/cf/3e452fbd9597bcd8058856ecd42b22751749d07935793a1856d988154151/ruff-0.11.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b56697e5b8bcf1d61293ccfe63873aba08fdbcbbba839fc046ec5926bdb25a3a", size = 12460807 }, + { url = "https://files.pythonhosted.org/packages/2f/ec/8f170381a15e1eb7d93cb4feef8d17334d5a1eb33fee273aee5d1f8241a3/ruff-0.11.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d47afa45e7b0eaf5e5969c6b39cbd108be83910b5c74626247e366fd7a36a13", size = 12063261 }, + { url = "https://files.pythonhosted.org/packages/0d/bf/57208f8c0a8153a14652a85f4116c0002148e83770d7a41f2e90b52d2b4e/ruff-0.11.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bf9603fe1bf949de8b09a2da896f05c01ed7a187f4a386cdba6760e7f61be", size = 11329601 }, + { url = "https://files.pythonhosted.org/packages/c3/56/edf942f7fdac5888094d9ffa303f12096f1a93eb46570bcf5f14c0c70880/ruff-0.11.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08033320e979df3b20dba567c62f69c45e01df708b0f9c83912d7abd3e0801cd", size = 11522186 }, + { url = "https://files.pythonhosted.org/packages/ed/63/79ffef65246911ed7e2290aeece48739d9603b3a35f9529fec0fc6c26400/ruff-0.11.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:929b7706584f5bfd61d67d5070f399057d07c70585fa8c4491d78ada452d3bef", size = 10449032 }, + { url = "https://files.pythonhosted.org/packages/88/19/8c9d4d8a1c2a3f5a1ea45a64b42593d50e28b8e038f1aafd65d6b43647f3/ruff-0.11.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7de4a73205dc5756b8e09ee3ed67c38312dce1aa28972b93150f5751199981b5", size = 10129370 }, + { url = "https://files.pythonhosted.org/packages/bc/0f/2d15533eaa18f460530a857e1778900cd867ded67f16c85723569d54e410/ruff-0.11.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2635c2a90ac1b8ca9e93b70af59dfd1dd2026a40e2d6eebaa3efb0465dd9cf02", size = 11123529 }, + { url = "https://files.pythonhosted.org/packages/4f/e2/4c2ac669534bdded835356813f48ea33cfb3a947dc47f270038364587088/ruff-0.11.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:d05d6a78a89166f03f03a198ecc9d18779076ad0eec476819467acb401028c0c", size = 11577642 }, + { url = "https://files.pythonhosted.org/packages/a7/9b/c9ddf7f924d5617a1c94a93ba595f4b24cb5bc50e98b94433ab3f7ad27e5/ruff-0.11.12-py3-none-win32.whl", hash = "sha256:f5a07f49767c4be4772d161bfc049c1f242db0cfe1bd976e0f0886732a4765d6", size = 10475511 }, + { url = "https://files.pythonhosted.org/packages/fd/d6/74fb6d3470c1aada019ffff33c0f9210af746cca0a4de19a1f10ce54968a/ruff-0.11.12-py3-none-win_amd64.whl", hash = "sha256:5a4d9f8030d8c3a45df201d7fb3ed38d0219bccd7955268e863ee4a115fa0832", size = 11523573 }, + { url = "https://files.pythonhosted.org/packages/44/42/d58086ec20f52d2b0140752ae54b355ea2be2ed46f914231136dd1effcc7/ruff-0.11.12-py3-none-win_arm64.whl", hash = "sha256:65194e37853158d368e333ba282217941029a28ea90913c67e558c611d04daa5", size = 10697770 }, ] [[package]] @@ -5173,38 +5132,38 @@ wheels = [ [[package]] name = "setuptools" -version = "80.4.0" +version = "80.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/0cc40fe41fd2adb80a2f388987f4f8db3c866c69e33e0b4c8b093fdf700e/setuptools-80.4.0.tar.gz", hash = "sha256:5a78f61820bc088c8e4add52932ae6b8cf423da2aff268c23f813cfbb13b4006", size = 1315008 } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/93/dba5ed08c2e31ec7cdc2ce75705a484ef0be1a2fecac8a58272489349de8/setuptools-80.4.0-py3-none-any.whl", hash = "sha256:6cdc8cb9a7d590b237dbe4493614a9b75d0559b888047c1f67d49ba50fc3edb2", size = 1200812 }, + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486 }, ] [[package]] name = "shapely" -version = "2.1.0" +version = "2.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/fe/3b0d2f828ffaceadcdcb51b75b9c62d98e62dd95ce575278de35f24a1c20/shapely-2.1.0.tar.gz", hash = "sha256:2cbe90e86fa8fc3ca8af6ffb00a77b246b918c7cf28677b7c21489b678f6b02e", size = 313617 } +sdist = { url = "https://files.pythonhosted.org/packages/ca/3c/2da625233f4e605155926566c0e7ea8dda361877f48e8b1655e53456f252/shapely-2.1.1.tar.gz", hash = "sha256:500621967f2ffe9642454808009044c21e5b35db89ce69f8a2042c2ffd0e2772", size = 315422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/37/ae448f06f363ff3dfe4bae890abd842c4e3e9edaf01245dbc9b97008c9e6/shapely-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c8323031ef7c1bdda7a92d5ddbc7b6b62702e73ba37e9a8ccc8da99ec2c0b87c", size = 1820974 }, - { url = "https://files.pythonhosted.org/packages/78/da/ea2a898e93c6953c5eef353a0e1781a0013a1352f2b90aa9ab0b800e0c75/shapely-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4da7c6cd748d86ec6aace99ad17129d30954ccf5e73e9911cdb5f0fa9658b4f8", size = 1624137 }, - { url = "https://files.pythonhosted.org/packages/64/4a/f903f82f0fabcd3f43ea2e8132cabda079119247330a9fe58018c39c4e22/shapely-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f0cdf85ff80831137067e7a237085a3ee72c225dba1b30beef87f7d396cf02b", size = 2957161 }, - { url = "https://files.pythonhosted.org/packages/92/07/3e2738c542d73182066196b8ce99388cb537d19e300e428d50b1537e3b21/shapely-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f2be5d79aac39886f23000727cf02001aef3af8810176c29ee12cdc3ef3a50", size = 3078530 }, - { url = "https://files.pythonhosted.org/packages/82/08/32210e63d8f8af9142d37c2433ece4846862cdac91a0fe66f040780a71bd/shapely-2.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:21a4515009f56d7a159cf5c2554264e82f56405b4721f9a422cb397237c5dca8", size = 3902208 }, - { url = "https://files.pythonhosted.org/packages/19/0e/0abb5225f8a32fbdb615476637038a7d2db40c0af46d1bb3a08b869bee39/shapely-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:15cebc323cec2cb6b2eaa310fdfc621f6dbbfaf6bde336d13838fcea76c885a9", size = 4082863 }, - { url = "https://files.pythonhosted.org/packages/f8/1b/7cd816fd388108c872ab7e2930180b02d0c34891213f361e4a66e5e032f2/shapely-2.1.0-cp311-cp311-win32.whl", hash = "sha256:cad51b7a5c8f82f5640472944a74f0f239123dde9a63042b3c5ea311739b7d20", size = 1527488 }, - { url = "https://files.pythonhosted.org/packages/fd/28/7bb5b1944d4002d4b2f967762018500381c3b532f98e456bbda40c3ded68/shapely-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d4005309dde8658e287ad9c435c81877f6a95a9419b932fa7a1f34b120f270ae", size = 1708311 }, - { url = "https://files.pythonhosted.org/packages/4e/d1/6a9371ec39d3ef08e13225594e6c55b045209629afd9e6d403204507c2a8/shapely-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53e7ee8bd8609cf12ee6dce01ea5affe676976cf7049315751d53d8db6d2b4b2", size = 1830732 }, - { url = "https://files.pythonhosted.org/packages/32/87/799e3e48be7ce848c08509b94d2180f4ddb02e846e3c62d0af33da4d78d3/shapely-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3cab20b665d26dbec0b380e15749bea720885a481fa7b1eedc88195d4a98cfa4", size = 1638404 }, - { url = "https://files.pythonhosted.org/packages/85/00/6665d77f9dd09478ab0993b8bc31668aec4fd3e5f1ddd1b28dd5830e47be/shapely-2.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a38b39a09340273c3c92b3b9a374272a12cc7e468aeeea22c1c46217a03e5c", size = 2945316 }, - { url = "https://files.pythonhosted.org/packages/34/49/738e07d10bbc67cae0dcfe5a484c6e518a517f4f90550dda2adf3a78b9f2/shapely-2.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:edaec656bdd9b71278b98e6f77c464b1c3b2daa9eace78012ff0f0b4b5b15b04", size = 3063099 }, - { url = "https://files.pythonhosted.org/packages/88/b8/138098674559362ab29f152bff3b6630de423378fbb0324812742433a4ef/shapely-2.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c8a732ddd9b25e7a54aa748e7df8fd704e23e5d5d35b7d376d80bffbfc376d04", size = 3887873 }, - { url = "https://files.pythonhosted.org/packages/67/a8/fdae7c2db009244991d86f4d2ca09d2f5ccc9d41c312c3b1ee1404dc55da/shapely-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9c93693ad8adfdc9138a5a2d42da02da94f728dd2e82d2f0f442f10e25027f5f", size = 4067004 }, - { url = "https://files.pythonhosted.org/packages/ed/78/17e17d91b489019379df3ee1afc4bd39787b232aaa1d540f7d376f0280b7/shapely-2.1.0-cp312-cp312-win32.whl", hash = "sha256:d8ac6604eefe807e71a908524de23a37920133a1729fe3a4dfe0ed82c044cbf4", size = 1527366 }, - { url = "https://files.pythonhosted.org/packages/b8/bd/9249bd6dda948441e25e4fb14cbbb5205146b0fff12c66b19331f1ff2141/shapely-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:f4f47e631aa4f9ec5576eac546eb3f38802e2f82aeb0552f9612cb9a14ece1db", size = 1708265 }, + { url = "https://files.pythonhosted.org/packages/19/97/2df985b1e03f90c503796ad5ecd3d9ed305123b64d4ccb54616b30295b29/shapely-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587a1aa72bc858fab9b8c20427b5f6027b7cbc92743b8e2c73b9de55aa71c7a7", size = 1819368 }, + { url = "https://files.pythonhosted.org/packages/56/17/504518860370f0a28908b18864f43d72f03581e2b6680540ca668f07aa42/shapely-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9fa5c53b0791a4b998f9ad84aad456c988600757a96b0a05e14bba10cebaaaea", size = 1625362 }, + { url = "https://files.pythonhosted.org/packages/36/a1/9677337d729b79fce1ef3296aac6b8ef4743419086f669e8a8070eff8f40/shapely-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aabecd038841ab5310d23495253f01c2a82a3aedae5ab9ca489be214aa458aa7", size = 2999005 }, + { url = "https://files.pythonhosted.org/packages/a2/17/e09357274699c6e012bbb5a8ea14765a4d5860bb658df1931c9f90d53bd3/shapely-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:586f6aee1edec04e16227517a866df3e9a2e43c1f635efc32978bb3dc9c63753", size = 3108489 }, + { url = "https://files.pythonhosted.org/packages/17/5d/93a6c37c4b4e9955ad40834f42b17260ca74ecf36df2e81bb14d12221b90/shapely-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b9878b9e37ad26c72aada8de0c9cfe418d9e2ff36992a1693b7f65a075b28647", size = 3945727 }, + { url = "https://files.pythonhosted.org/packages/a3/1a/ad696648f16fd82dd6bfcca0b3b8fbafa7aacc13431c7fc4c9b49e481681/shapely-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9a531c48f289ba355e37b134e98e28c557ff13965d4653a5228d0f42a09aed0", size = 4109311 }, + { url = "https://files.pythonhosted.org/packages/d4/38/150dd245beab179ec0d4472bf6799bf18f21b1efbef59ac87de3377dbf1c/shapely-2.1.1-cp311-cp311-win32.whl", hash = "sha256:4866de2673a971820c75c0167b1f1cd8fb76f2d641101c23d3ca021ad0449bab", size = 1522982 }, + { url = "https://files.pythonhosted.org/packages/93/5b/842022c00fbb051083c1c85430f3bb55565b7fd2d775f4f398c0ba8052ce/shapely-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:20a9d79958b3d6c70d8a886b250047ea32ff40489d7abb47d01498c704557a93", size = 1703872 }, + { url = "https://files.pythonhosted.org/packages/fb/64/9544dc07dfe80a2d489060791300827c941c451e2910f7364b19607ea352/shapely-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2827365b58bf98efb60affc94a8e01c56dd1995a80aabe4b701465d86dcbba43", size = 1833021 }, + { url = "https://files.pythonhosted.org/packages/07/aa/fb5f545e72e89b6a0f04a0effda144f5be956c9c312c7d4e00dfddbddbcf/shapely-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9c551f7fa7f1e917af2347fe983f21f212863f1d04f08eece01e9c275903fad", size = 1643018 }, + { url = "https://files.pythonhosted.org/packages/03/46/61e03edba81de729f09d880ce7ae5c1af873a0814206bbfb4402ab5c3388/shapely-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78dec4d4fbe7b1db8dc36de3031767e7ece5911fb7782bc9e95c5cdec58fb1e9", size = 2986417 }, + { url = "https://files.pythonhosted.org/packages/1f/1e/83ec268ab8254a446b4178b45616ab5822d7b9d2b7eb6e27cf0b82f45601/shapely-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:872d3c0a7b8b37da0e23d80496ec5973c4692920b90de9f502b5beb994bbaaef", size = 3098224 }, + { url = "https://files.pythonhosted.org/packages/f1/44/0c21e7717c243e067c9ef8fa9126de24239f8345a5bba9280f7bb9935959/shapely-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2e2b9125ebfbc28ecf5353511de62f75a8515ae9470521c9a693e4bb9fbe0cf1", size = 3925982 }, + { url = "https://files.pythonhosted.org/packages/15/50/d3b4e15fefc103a0eb13d83bad5f65cd6e07a5d8b2ae920e767932a247d1/shapely-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4b96cea171b3d7f6786976a0520f178c42792897653ecca0c5422fb1e6946e6d", size = 4089122 }, + { url = "https://files.pythonhosted.org/packages/bd/05/9a68f27fc6110baeedeeebc14fd86e73fa38738c5b741302408fb6355577/shapely-2.1.1-cp312-cp312-win32.whl", hash = "sha256:39dca52201e02996df02e447f729da97cfb6ff41a03cb50f5547f19d02905af8", size = 1522437 }, + { url = "https://files.pythonhosted.org/packages/bc/e9/a4560e12b9338842a1f82c9016d2543eaa084fce30a1ca11991143086b57/shapely-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:13d643256f81d55a50013eff6321142781cf777eb6a9e207c2c9e6315ba6044a", size = 1703479 }, ] [[package]] @@ -5292,11 +5251,11 @@ wheels = [ [[package]] name = "sqlglot" -version = "26.17.1" +version = "26.24.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/86/461568bd63a43fd3c9d2dec42f9070905cd7b1a0a7e27cacfe91c2e386ff/sqlglot-26.17.1.tar.gz", hash = "sha256:518c649ff4ae9601e2f156758c21d3552db8a109872f1228e0f6e89d3712bf73", size = 5356122 } +sdist = { url = "https://files.pythonhosted.org/packages/4d/f7/0fa9f9f2477c4e3d8e28b0f5e066f0e72343c29c8a302ee6a77579e8986b/sqlglot-26.24.0.tar.gz", hash = "sha256:e778ca9cb685b4fc34b59d50432c20f463c63ec90d0448fa91afa7f320a88518", size = 5371208 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/30/2b50dd8bc227cce28aa7cb4dfa8fc174d34d1b7fb65128055d308ab6af7a/sqlglot-26.17.1-py3-none-any.whl", hash = "sha256:8772f5c1d095a9600cfbe5bdd08bc345d84f875773735a6cbe6cd5abcfa43900", size = 460536 }, + { url = "https://files.pythonhosted.org/packages/b2/11/6995759d913d714ff443478f5865b2616dbcd32b12764d02df9550d7a61e/sqlglot-26.24.0-py3-none-any.whl", hash = "sha256:81f7e47bb1b4b396c564359f47c7c1aee476575a0cadf84dc35f7189cab87f82", size = 464043 }, ] [[package]] @@ -5584,7 +5543,7 @@ wheels = [ [[package]] name = "typer" -version = "0.15.3" +version = "0.16.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -5592,18 +5551,18 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/1a/5f36851f439884bcfe8539f6a20ff7516e7b60f319bbaf69a90dc35cc2eb/typer-0.15.3.tar.gz", hash = "sha256:818873625d0569653438316567861899f7e9972f2e6e0c16dab608345ced713c", size = 101641 } +sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/20/9d953de6f4367163d23ec823200eb3ecb0050a2609691e512c8b95827a9b/typer-0.15.3-py3-none-any.whl", hash = "sha256:c86a65ad77ca531f03de08d1b9cb67cd09ad02ddddf4b34745b5008f43b239bd", size = 45253 }, + { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317 }, ] [[package]] name = "types-aiofiles" -version = "24.1.0.20250326" +version = "24.1.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8d/25/c76a9ee91eefac376ed8905b029272e27c44739e3f148faf5c00afe71e43/types_aiofiles-24.1.0.20250326.tar.gz", hash = "sha256:c4bbe432fd043911ba83fb635456f5cc54f6d05fda2aadf6bef12a84f07a6efe", size = 14369 } +sdist = { url = "https://files.pythonhosted.org/packages/b3/13/41faafda1d85fc8afa744ee67a2d788b3ba63e5f1c7303e5d10c2d784d2d/types_aiofiles-24.1.0.20250516.tar.gz", hash = "sha256:7fd2a7f793bbe180b7b22cd4f59300fe61fdc9940b3bbc9899ffe32849b95188", size = 14304 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/18/1016ffd4c7775f24371f6a0309483dc5597e8245b5add67924e54ea3b83a/types_aiofiles-24.1.0.20250326-py3-none-any.whl", hash = "sha256:dfb58c9aa18bd449e80fb5d7f49dc3dd20d31de920a46223a61798ee4a521a70", size = 14344 }, + { url = "https://files.pythonhosted.org/packages/70/e7/828287ba5d1107db1093a123fe8e481eb5aab55c911f1100f28d0df80d5a/types_aiofiles-24.1.0.20250516-py3-none-any.whl", hash = "sha256:ec265994629146804b656a971c46f393ce860305834b3cacb4b8b6fb7dba7e33", size = 14253 }, ] [[package]] @@ -5617,14 +5576,14 @@ wheels = [ [[package]] name = "types-beautifulsoup4" -version = "4.12.0.20250204" +version = "4.12.0.20250516" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-html5lib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/11/6c/00fd71754ac3babe121c73b52e0de7ec05acd627edcb7ee652223c084d69/types_beautifulsoup4-4.12.0.20250204.tar.gz", hash = "sha256:f083d8edcbd01279f8c3995b56cfff2d01f1bb894c3b502ba118d36fbbc495bf", size = 16641 } +sdist = { url = "https://files.pythonhosted.org/packages/6d/d1/32b410f6d65eda94d3dfb0b3d0ca151f12cb1dc4cef731dcf7cbfd8716ff/types_beautifulsoup4-4.12.0.20250516.tar.gz", hash = "sha256:aa19dd73b33b70d6296adf92da8ab8a0c945c507e6fb7d5db553415cc77b417e", size = 16628 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/ec/9097e9f7f5901e4d7834c7e0bc8f775f9ffa448ae31471457a1ebafeb4c5/types_beautifulsoup4-4.12.0.20250204-py3-none-any.whl", hash = "sha256:57ce9e75717b63c390fd789c787d267a67eb01fa6d800a03b9bdde2e877ed1eb", size = 17061 }, + { url = "https://files.pythonhosted.org/packages/7c/79/d84de200a80085b32f12c5820d4fd0addcbe7ba6dce8c1c9d8605e833c8e/types_beautifulsoup4-4.12.0.20250516-py3-none-any.whl", hash = "sha256:5923399d4a1ba9cc8f0096fe334cc732e130269541d66261bb42ab039c0376ee", size = 16879 }, ] [[package]] @@ -5636,6 +5595,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/27/4d/fd7cc050e2d236d5570c4d92531c0396573a1e14b31735870e849351c717/types_cachetools-5.5.0.20240820-py3-none-any.whl", hash = "sha256:efb2ed8bf27a4b9d3ed70d33849f536362603a90b8090a328acf0cd42fda82e2", size = 4149 }, ] +[[package]] +name = "types-cffi" +version = "1.17.0.20250523" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "types-setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f7/5f/ac80a2f55757019e5d4809d17544569c47a623565258ca1a836ba951d53f/types_cffi-1.17.0.20250523.tar.gz", hash = "sha256:e7110f314c65590533adae1b30763be08ca71ad856a1ae3fe9b9d8664d49ec22", size = 16858 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/86/e26e6ae4dfcbf6031b8422c22cf3a9eb2b6d127770406e7645b6248d8091/types_cffi-1.17.0.20250523-py3-none-any.whl", hash = "sha256:e98c549d8e191f6220e440f9f14315d6775a21a0e588c32c20476be885b2fad9", size = 20010 }, +] + [[package]] name = "types-colorama" version = "0.4.15.20240311" @@ -5647,11 +5618,11 @@ wheels = [ [[package]] name = "types-defusedxml" -version = "0.7.0.20240218" +version = "0.7.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/04/acc0a4ef3ea7eff334e3bc73e7a7af54f06684dfea405c0c81fb28a243ab/types-defusedxml-0.7.0.20240218.tar.gz", hash = "sha256:05688a7724dc66ea74c4af5ca0efc554a150c329cb28c13a64902cab878d06ed", size = 5493 } +sdist = { url = "https://files.pythonhosted.org/packages/55/9d/3ba8b80536402f1a125bc5a44d82ab686aafa55a85f56160e076b2ac30de/types_defusedxml-0.7.0.20250516.tar.gz", hash = "sha256:164c2945077fa450f24ed09633f8b3a80694687fefbbc1cba5f24e4ba570666b", size = 10298 } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/a3/6c007483045d362f45cc30955eb07644a3e8a0d57ee6293f5b540b127558/types_defusedxml-0.7.0.20240218-py3-none-any.whl", hash = "sha256:2b7f3c5ca14fdbe728fab0b846f5f7eb98c4bd4fd2b83d25f79e923caa790ced", size = 7827 }, + { url = "https://files.pythonhosted.org/packages/2e/7b/567b0978150edccf7fa3aa8f2566ea9c3ffc9481ce7d64428166934d6d7f/types_defusedxml-0.7.0.20250516-py3-none-any.whl", hash = "sha256:00e793e5c385c3e142d7c2acc3b4ccea2fe0828cee11e35501f0ba40386630a0", size = 12576 }, ] [[package]] @@ -5665,11 +5636,11 @@ wheels = [ [[package]] name = "types-docutils" -version = "0.21.0.20241128" +version = "0.21.0.20250526" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dd/df/64e7ab01a4fc5ce46895dc94e31cffc8b8087c8d91ee54c45ac2d8d82445/types_docutils-0.21.0.20241128.tar.gz", hash = "sha256:4dd059805b83ac6ec5a223699195c4e9eeb0446a4f7f2aeff1759a4a7cc17473", size = 26739 } +sdist = { url = "https://files.pythonhosted.org/packages/34/bf/bb5695f7a9660f79a9cd999ea13ff7331b8f2d03aec3d2fd7c38be4bc8aa/types_docutils-0.21.0.20250526.tar.gz", hash = "sha256:6c7ba387716315df0d86a796baec9d5a71825ed2746cb7763193aafbb70ac86c", size = 38140 } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/b6/10ba95739f2cbb9c5bd2f6568148d62b468afe01a94c633e8892a2936d8a/types_docutils-0.21.0.20241128-py3-none-any.whl", hash = "sha256:e0409204009639e9b0bf4521eeabe58b5e574ce9c0db08421c2ac26c32be0039", size = 34677 }, + { url = "https://files.pythonhosted.org/packages/35/84/73bca8d1364f6685bd6e00eaa15e653ef96163231fbd7a612f3a845497fb/types_docutils-0.21.0.20250526-py3-none-any.whl", hash = "sha256:44d9f9ed19bb75071deb6804947c123f30bbc617a656420f044e09b9f16b72d1", size = 62000 }, ] [[package]] @@ -5721,32 +5692,32 @@ wheels = [ [[package]] name = "types-html5lib" -version = "1.1.11.20241018" +version = "1.1.11.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/9d/f6fbcc8246f5e46845b4f989c4e17e6fb3ce572f7065b185e515bf8a3be7/types-html5lib-1.1.11.20241018.tar.gz", hash = "sha256:98042555ff78d9e3a51c77c918b1041acbb7eb6c405408d8a9e150ff5beccafa", size = 11370 } +sdist = { url = "https://files.pythonhosted.org/packages/d0/ed/9f092ff479e2b5598941855f314a22953bb04b5fb38bcba3f880feb833ba/types_html5lib-1.1.11.20250516.tar.gz", hash = "sha256:65043a6718c97f7d52567cc0cdf41efbfc33b1f92c6c0c5e19f60a7ec69ae720", size = 16136 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/7c/f862b1dc31268ef10fe95b43dcdf216ba21a592fafa2d124445cd6b92e93/types_html5lib-1.1.11.20241018-py3-none-any.whl", hash = "sha256:3f1e064d9ed2c289001ae6392c84c93833abb0816165c6ff0abfc304a779f403", size = 17292 }, + { url = "https://files.pythonhosted.org/packages/cc/3b/cb5b23c7b51bf48b8c9f175abb9dce2f1ecd2d2c25f92ea9f4e3720e9398/types_html5lib-1.1.11.20250516-py3-none-any.whl", hash = "sha256:5e407b14b1bd2b9b1107cbd1e2e19d4a0c46d60febd231c7ab7313d7405663c1", size = 21770 }, ] [[package]] name = "types-jmespath" -version = "1.0.2.20240106" +version = "1.0.2.20250529" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/e4/1f7414dbca03975f66f1ab1b3f7b3deb7c19b104ef14dd3c99036bbc39b2/types-jmespath-1.0.2.20240106.tar.gz", hash = "sha256:b4a65a116bfc1c700a4fd9d24e2e397f4a431122e0320a77b7f1989a6b5d819e", size = 5071 } +sdist = { url = "https://files.pythonhosted.org/packages/ab/ce/1083f6dcf5e7f25e9abcb67f870799d45f8b184cdb6fd23bbe541d17d9cc/types_jmespath-1.0.2.20250529.tar.gz", hash = "sha256:d3c08397f57fe0510e3b1b02c27f0a5e738729680fb0ea5f4b74f70fb032c129", size = 10138 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/30/3d6443f782601dd88820ba31e7668abfec7e19d685ac7f6fbcfd6ebba519/types_jmespath-1.0.2.20240106-py3-none-any.whl", hash = "sha256:c3e715fcaae9e5f8d74e14328fdedc4f2b3f0e18df17f3e457ae0a18e245bde0", size = 6087 }, + { url = "https://files.pythonhosted.org/packages/66/74/78c518aeb310cc809aaf1dd19e646f8d42c472344a720b39e1ba2a65c2e7/types_jmespath-1.0.2.20250529-py3-none-any.whl", hash = "sha256:6344c102233aae954d623d285618079d797884e35f6cd8d2a894ca02640eca07", size = 11409 }, ] [[package]] name = "types-jsonschema" -version = "4.23.0.20241208" +version = "4.23.0.20250516" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/e6/9e5cd771687086844caa43dbb211ec0d1cfa899d17c110f3220efcd46e83/types_jsonschema-4.23.0.20241208.tar.gz", hash = "sha256:e8b15ad01f290ecf6aea53f93fbdf7d4730e4600313e89e8a7f95622f7e87b7c", size = 14770 } +sdist = { url = "https://files.pythonhosted.org/packages/a0/ec/27ea5bffdb306bf261f6677a98b6993d93893b2c2e30f7ecc1d2c99d32e7/types_jsonschema-4.23.0.20250516.tar.gz", hash = "sha256:9ace09d9d35c4390a7251ccd7d833b92ccc189d24d1b347f26212afce361117e", size = 14911 } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/64/4b2fba8b7cb0104ba013f2a1bf6f39a98e927e14befe1ef947d373b25218/types_jsonschema-4.23.0.20241208-py3-none-any.whl", hash = "sha256:87934bd9231c99d8eff94cacfc06ba668f7973577a9bd9e1f9de957c5737313e", size = 15021 }, + { url = "https://files.pythonhosted.org/packages/e6/48/73ae8b388e19fc4a2a8060d0876325ec7310cfd09b53a2185186fd35959f/types_jsonschema-4.23.0.20250516-py3-none-any.whl", hash = "sha256:e7d0dd7db7e59e63c26e3230e26ffc64c4704cc5170dc21270b366a35ead1618", size = 15027 }, ] [[package]] @@ -5760,11 +5731,11 @@ wheels = [ [[package]] name = "types-oauthlib" -version = "3.2.0.20250408" +version = "3.2.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/03/d746efe82f8c04feea6c527df2a77a89b84eb71e931279d9d1f180644037/types_oauthlib-3.2.0.20250408.tar.gz", hash = "sha256:8fceb310ee5da1f767428a3cb932cba60b281259322743e4b1321409b911ae0e", size = 23977 } +sdist = { url = "https://files.pythonhosted.org/packages/b1/2c/dba2c193ccff2d1e2835589d4075b230d5627b9db363e9c8de153261d6ec/types_oauthlib-3.2.0.20250516.tar.gz", hash = "sha256:56bf2cffdb8443ae718d4e83008e3fbd5f861230b4774e6d7799527758119d9a", size = 24683 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/d6/3fa44b77354441a4c4c8b0c6dc534e94b46013aa6ea20d9c7e3fe7d391c1/types_oauthlib-3.2.0.20250408-py3-none-any.whl", hash = "sha256:1a41f0e18beeae05764f910ae59cc5df877807ae8c9e6f03f5f3af15ae4b9c01", size = 44485 }, + { url = "https://files.pythonhosted.org/packages/b8/54/cdd62283338616fd2448f534b29110d79a42aaabffaf5f45e7aed365a366/types_oauthlib-3.2.0.20250516-py3-none-any.whl", hash = "sha256:5799235528bc9bd262827149a1633ff55ae6e5a5f5f151f4dae74359783a31b3", size = 45671 }, ] [[package]] @@ -5787,20 +5758,20 @@ wheels = [ [[package]] name = "types-openpyxl" -version = "3.1.5.20250506" +version = "3.1.5.20250602" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/97/1a/063e0c279d359b68cc8444e5281057a2ffacf661e48398712c64fef75eb6/types_openpyxl-3.1.5.20250506.tar.gz", hash = "sha256:c82d748895dbedd59ef36ba6b0079c588c4d1d302311b406752845c83aa4c707", size = 100483 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/d4/33cc2f331cde82206aa4ec7d8db408beca65964785f438c6d2505d828178/types_openpyxl-3.1.5.20250602.tar.gz", hash = "sha256:d19831482022fc933780d6e9d6990464c18c2ec5f14786fea862f72c876980b5", size = 100608 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/84/c813f40a325327f7673a3b6c8c98c4ea71c4cb84a129523e507ed6fa9e1d/types_openpyxl-3.1.5.20250506-py3-none-any.whl", hash = "sha256:7fe8cb309d11edc3d9f1a778823f49d77422c59352180fc066607854b22e9683", size = 166054 }, + { url = "https://files.pythonhosted.org/packages/2e/69/5b924a20a4d441ec2160e94085b9fa9358dc27edde10080d71209c59101d/types_openpyxl-3.1.5.20250602-py3-none-any.whl", hash = "sha256:1f82211e086902318f6a14b5d8d865102362fda7cb82f3d63ac4dff47a1f164b", size = 165922 }, ] [[package]] name = "types-pexpect" -version = "4.9.0.20241208" +version = "4.9.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/8b/2ac0c1db88bdc441d21477f151a074b1789aa3a4deac571b079a097bd987/types_pexpect-4.9.0.20241208.tar.gz", hash = "sha256:bbca0d0819947a719989a5cfe83641d9212bef893e2f0a7a01e47926bc82401d", size = 13222 } +sdist = { url = "https://files.pythonhosted.org/packages/92/a3/3943fcb94c12af29a88c346b588f1eda180b8b99aeb388a046b25072732c/types_pexpect-4.9.0.20250516.tar.gz", hash = "sha256:7baed9ee566fa24034a567cbec56a5cff189a021344e84383b14937b35d83881", size = 13285 } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/c6/14c23e04bae6a83e051da86c1670684e59acadab333a8497384aa201defd/types_pexpect-4.9.0.20241208-py3-none-any.whl", hash = "sha256:1928f478528454f0fea3495c16cf1ee2e67fca5c9fe97d60b868ac48c1fd5633", size = 17085 }, + { url = "https://files.pythonhosted.org/packages/e1/d4/3128ae3365b46b9c4a33202af79b0e0d9d4308a6348a3317ce2331fea6cb/types_pexpect-4.9.0.20250516-py3-none-any.whl", hash = "sha256:84cbd7ae9da577c0d2629d4e4fd53cf074cd012296e01fd4fa1031e01973c28a", size = 17081 }, ] [[package]] @@ -5814,77 +5785,90 @@ wheels = [ [[package]] name = "types-psutil" -version = "7.0.0.20250401" +version = "7.0.0.20250601" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ef/fc/3829cb113aa05c268b18369f1f003a4589216931658ebfa69e3d4931ba60/types_psutil-7.0.0.20250401.tar.gz", hash = "sha256:2a7d663c0888a079fc1643ebc109ad12e57a21c9552a9e2035da504191336dbf", size = 20273 } +sdist = { url = "https://files.pythonhosted.org/packages/c8/af/767b92be7de4105f5e2e87a53aac817164527c4a802119ad5b4e23028f7c/types_psutil-7.0.0.20250601.tar.gz", hash = "sha256:71fe9c4477a7e3d4f1233862f0877af87bff057ff398f04f4e5c0ca60aded197", size = 20297 } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/42/45e01f3bce242c0caad36b968114a00f454169df6c771c092c96727239d8/types_psutil-7.0.0.20250401-py3-none-any.whl", hash = "sha256:ed23f7140368104afe4e05a6085a5fa56fbe8c880a0f4dfe8d63e041106071ed", size = 23173 }, + { url = "https://files.pythonhosted.org/packages/8d/85/864c663a924a34e0d87bd10ead4134bb4ab6269fa02daaa5dd644ac478c5/types_psutil-7.0.0.20250601-py3-none-any.whl", hash = "sha256:0c372e2d1b6529938a080a6ba4a9358e3dfc8526d82fabf40c1ef9325e4ca52e", size = 23106 }, ] [[package]] name = "types-psycopg2" -version = "2.9.21.20250318" +version = "2.9.21.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/29/9e86192ffa0a7ffc48d222f510026ec92aa93c7321ee24128480553661ec/types_psycopg2-2.9.21.20250318.tar.gz", hash = "sha256:eb6eac5bfb16adfd5f16b818918b9e26a40ede147e0f2bbffdf53a6ef7025a87", size = 26614 } +sdist = { url = "https://files.pythonhosted.org/packages/68/55/3f94eff9d1a1402f39e19523a90117fe6c97d7fc61957e7ee3e3052c75e1/types_psycopg2-2.9.21.20250516.tar.gz", hash = "sha256:6721018279175cce10b9582202e2a2b4a0da667857ccf82a97691bdb5ecd610f", size = 26514 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/9c/34da1d5c2fe53c91f3382f45e18c58141cebef38e7204f676a93d1af6a1c/types_psycopg2-2.9.21.20250318-py3-none-any.whl", hash = "sha256:7296d111ad950bbd2fc979a1ab0572acae69047f922280e77db657c00d2c79c0", size = 24939 }, + { url = "https://files.pythonhosted.org/packages/39/50/f5d74945ab09b9a3e966ad39027ac55998f917eca72ede7929eab962b5db/types_psycopg2-2.9.21.20250516-py3-none-any.whl", hash = "sha256:2a9212d1e5e507017b31486ce8147634d06b85d652769d7a2d91d53cb4edbd41", size = 24846 }, ] [[package]] name = "types-pygments" -version = "2.19.0.20250305" +version = "2.19.0.20250516" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-docutils" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e6/be/88f777c75022b111f9e9fe4cdb430bf92892fe90188b0fd037601ded2ea1/types_pygments-2.19.0.20250305.tar.gz", hash = "sha256:044c50e80ecd4128c00a7268f20355e16f5c55466d3d49dfda09be920af40b4b", size = 18521 } +sdist = { url = "https://files.pythonhosted.org/packages/71/9a/c1ea3f59001e9d13b93ec8acf02c75b47832423f17471295b8ceebc48a65/types_pygments-2.19.0.20250516.tar.gz", hash = "sha256:b53fd07e197f0e7be38ee19598bd99c78be5ca5f9940849c843be74a2f81ab58", size = 18485 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/c6/b6d3ad345b76425e46d25a2da1758603d80c3a59405bdcbbbaa86d8c8070/types_pygments-2.19.0.20250305-py3-none-any.whl", hash = "sha256:ca88aae5ec426f9b107c0f7adc36dc096d2882d930a49f679eaf4b8b643db35d", size = 25638 }, + { url = "https://files.pythonhosted.org/packages/a7/0b/32ce3ad35983bf4f603c43cfb00559b37bb5ed90ac4ef9f1d5564b8e4034/types_pygments-2.19.0.20250516-py3-none-any.whl", hash = "sha256:db27de8b59591389cd7d14792483892c021c73b8389ef55fef40a48aa371fbcc", size = 25440 }, ] [[package]] name = "types-pymysql" -version = "1.1.0.20241103" +version = "1.1.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/ac/5a23decbcf53893df11636b7d61cc000a97b0ed45e09cee94d6c75f159ec/types-PyMySQL-1.1.0.20241103.tar.gz", hash = "sha256:a7628542919a0ba87625fb79eefb2a2de45fb4ad32afe6e561e8f2f27fb58b8c", size = 14987 } +sdist = { url = "https://files.pythonhosted.org/packages/db/11/cdaa90b82cb25c5e04e75f0b0616872aa5775b001096779375084f8dbbcf/types_pymysql-1.1.0.20250516.tar.gz", hash = "sha256:fea4a9776101cf893dfc868f42ce10d2e46dcc498c792cc7c9c0fe00cb744234", size = 19640 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/04/d02323dd4dfd6e0af4ecbb88a00215c37aa79894a2d158390700c84c8597/types_PyMySQL-1.1.0.20241103-py3-none-any.whl", hash = "sha256:1a32efd8a74b5bf74c4de92a86c1cc6edaf3802dcfd5546635ab501eb5e3c096", size = 15610 }, + { url = "https://files.pythonhosted.org/packages/ab/64/129656e04ddda35d69faae914ce67cf60d83407ddd7afdef1e7c50bbb74a/types_pymysql-1.1.0.20250516-py3-none-any.whl", hash = "sha256:41c87a832e3ff503d5120cc6cebd64f6dcb3c407d9580a98b2cb3e3bcd109aa6", size = 20328 }, +] + +[[package]] +name = "types-pyopenssl" +version = "24.1.0.20240722" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "types-cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/93/29/47a346550fd2020dac9a7a6d033ea03fccb92fa47c726056618cc889745e/types-pyOpenSSL-24.1.0.20240722.tar.gz", hash = "sha256:47913b4678a01d879f503a12044468221ed8576263c1540dcb0484ca21b08c39", size = 8458 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/05/c868a850b6fbb79c26f5f299b768ee0adc1f9816d3461dcf4287916f655b/types_pyOpenSSL-24.1.0.20240722-py3-none-any.whl", hash = "sha256:6a7a5d2ec042537934cfb4c9d4deb0e16c4c6250b09358df1f083682fe6fda54", size = 7499 }, ] [[package]] name = "types-python-dateutil" -version = "2.9.0.20241206" +version = "2.9.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/60/47d92293d9bc521cd2301e423a358abfac0ad409b3a1606d8fbae1321961/types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", size = 13802 } +sdist = { url = "https://files.pythonhosted.org/packages/ef/88/d65ed807393285204ab6e2801e5d11fbbea811adcaa979a2ed3b67a5ef41/types_python_dateutil-2.9.0.20250516.tar.gz", hash = "sha256:13e80d6c9c47df23ad773d54b2826bd52dbbb41be87c3f339381c1700ad21ee5", size = 13943 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53", size = 14384 }, + { url = "https://files.pythonhosted.org/packages/c5/3f/b0e8db149896005adc938a1e7f371d6d7e9eca4053a29b108978ed15e0c2/types_python_dateutil-2.9.0.20250516-py3-none-any.whl", hash = "sha256:2b2b3f57f9c6a61fba26a9c0ffb9ea5681c9b83e69cd897c6b5f668d9c0cab93", size = 14356 }, ] [[package]] name = "types-pytz" -version = "2025.2.0.20250326" +version = "2025.2.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4b/66/38c89861242f2c61c8315ddbcc7d7bbf64979f4b0bdc48db0ba62aeec330/types_pytz-2025.2.0.20250326.tar.gz", hash = "sha256:deda02de24f527066fc8d6a19e284ab3f3ae716a42b4adb6b40e75e408c08d36", size = 10595 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/72/b0e711fd90409f5a76c75349055d3eb19992c110f0d2d6aabbd6cfbc14bf/types_pytz-2025.2.0.20250516.tar.gz", hash = "sha256:e1216306f8c0d5da6dafd6492e72eb080c9a166171fa80dd7a1990fd8be7a7b3", size = 10940 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/e0/17f3a6670db5c95dc195f346e2e7290f22ba8327c188133959389b578cbd/types_pytz-2025.2.0.20250326-py3-none-any.whl", hash = "sha256:3c397fd1b845cd2b3adc9398607764ced9e578a98a5d1fbb4a9bc9253edfb162", size = 10222 }, + { url = "https://files.pythonhosted.org/packages/c1/ba/e205cd11c1c7183b23c97e4bcd1de7bc0633e2e867601c32ecfc6ad42675/types_pytz-2025.2.0.20250516-py3-none-any.whl", hash = "sha256:e0e0c8a57e2791c19f718ed99ab2ba623856b11620cb6b637e5f62ce285a7451", size = 10136 }, ] [[package]] name = "types-pywin32" -version = "310.0.0.20250429" +version = "310.0.0.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/b9/1876634fc40be589bb6fa1abf2741e4a9cbad6e29848dea1f73aab7c7182/types_pywin32-310.0.0.20250429.tar.gz", hash = "sha256:3efd94825c53fe9d996356215891141b9736584e835c83eb2bbf2fa573e9668c", size = 328388 } +sdist = { url = "https://files.pythonhosted.org/packages/6c/bc/c7be2934a37cc8c645c945ca88450b541e482c4df3ac51e5556377d34811/types_pywin32-310.0.0.20250516.tar.gz", hash = "sha256:91e5bfc033f65c9efb443722eff8101e31d690dd9a540fa77525590d3da9cc9d", size = 328459 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/17/987cac084174b9bd3e2d17c7a7bc2d2dff77303143ebe550a6b9d792a664/types_pywin32-310.0.0.20250429-py3-none-any.whl", hash = "sha256:1c7944ec77abe665d249678d24e141321ff8b8f755eca8b6c1e5c4b20e617e76", size = 390427 }, + { url = "https://files.pythonhosted.org/packages/9b/72/469e4cc32399dbe6c843e38fdb6d04fee755e984e137c0da502f74d3ac59/types_pywin32-310.0.0.20250516-py3-none-any.whl", hash = "sha256:f9ef83a1ec3e5aae2b0e24c5f55ab41272b5dfeaabb9a0451d33684c9545e41a", size = 390411 }, ] [[package]] name = "types-pyyaml" -version = "6.0.12.20250402" +version = "6.0.12.20250516" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/68/609eed7402f87c9874af39d35942744e39646d1ea9011765ec87b01b2a3c/types_pyyaml-6.0.12.20250402.tar.gz", hash = "sha256:d7c13c3e6d335b6af4b0122a01ff1d270aba84ab96d1a1a1063ecba3e13ec075", size = 17282 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/56/1fe61db05685fbb512c07ea9323f06ea727125951f1eb4dff110b3311da3/types_pyyaml-6.0.12.20250402-py3-none-any.whl", hash = "sha256:652348fa9e7a203d4b0d21066dfb00760d3cbd5a15ebb7cf8d33c88a49546681", size = 20329 }, + { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312 }, ] [[package]] @@ -5898,36 +5882,45 @@ wheels = [ [[package]] name = "types-requests" -version = "2.32.0.20250328" +version = "2.32.0.20250602" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/7d/eb174f74e3f5634eaacb38031bbe467dfe2e545bc255e5c90096ec46bc46/types_requests-2.32.0.20250328.tar.gz", hash = "sha256:c9e67228ea103bd811c96984fac36ed2ae8da87a36a633964a21f199d60baf32", size = 22995 } +sdist = { url = "https://files.pythonhosted.org/packages/48/b0/5321e6eeba5d59e4347fcf9bf06a5052f085c3aa0f4876230566d6a4dc97/types_requests-2.32.0.20250602.tar.gz", hash = "sha256:ee603aeefec42051195ae62ca7667cd909a2f8128fdf8aad9e8a5219ecfab3bf", size = 23042 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/15/3700282a9d4ea3b37044264d3e4d1b1f0095a4ebf860a99914fd544e3be3/types_requests-2.32.0.20250328-py3-none-any.whl", hash = "sha256:72ff80f84b15eb3aa7a8e2625fffb6a93f2ad5a0c20215fc1dcfa61117bcb2a2", size = 20663 }, + { url = "https://files.pythonhosted.org/packages/da/18/9b782980e575c6581d5c0c1c99f4c6f89a1d7173dad072ee96b2756c02e6/types_requests-2.32.0.20250602-py3-none-any.whl", hash = "sha256:f4f335f87779b47ce10b8b8597b409130299f6971ead27fead4fe7ba6ea3e726", size = 20638 }, ] [[package]] name = "types-requests-oauthlib" -version = "2.0.0.20250306" +version = "2.0.0.20250516" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-oauthlib" }, { name = "types-requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/52/acf02c00fb1005bbda26cd898b0bb5e832b0f2eb5b99a6fbab8e3edb30f2/types_requests_oauthlib-2.0.0.20250306.tar.gz", hash = "sha256:92e5f1ed35689b1804fdcd60b7ac39b0bd440a4b96693685879bc835b334797f", size = 11066 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/7b/1803a83dbccf0698a9fb70a444d12f1dcb0f49a5d8a6327a1e53fac19e15/types_requests_oauthlib-2.0.0.20250516.tar.gz", hash = "sha256:2a384b6ca080bd1eb30a88e14836237dc43d217892fddf869f03aea65213e0d4", size = 11034 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/b1/f4ba392a3341cd9d613f2dce855e82471073c5ec34996fe84ac3857956d0/types_requests_oauthlib-2.0.0.20250306-py3-none-any.whl", hash = "sha256:37707de81d9ce54894afcccd70d4a845dbe4c59e747908faaeba59a96453d993", size = 14446 }, + { url = "https://files.pythonhosted.org/packages/e8/3c/1bc76f1097cc4978cc97df11524f47559f8927fb2a2807375947bd185189/types_requests_oauthlib-2.0.0.20250516-py3-none-any.whl", hash = "sha256:faf417c259a3ae54c1b72c77032c07af3025ed90164c905fb785d21e8580139c", size = 14343 }, ] [[package]] name = "types-s3transfer" -version = "0.12.0" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/42/c1/45038f259d6741c252801044e184fec4dbaeff939a58f6160d7c32bf4975/types_s3transfer-0.13.0.tar.gz", hash = "sha256:203dadcb9865c2f68fb44bc0440e1dc05b79197ba4a641c0976c26c9af75ef52", size = 14175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/5d/6bbe4bf6a79fb727945291aef88b5ecbdba857a603f1bbcf1a6be0d3f442/types_s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:79c8375cbf48a64bff7654c02df1ec4b20d74f8c5672fc13e382f593ca5565b3", size = 19588 }, +] + +[[package]] +name = "types-setuptools" +version = "80.9.0.20250529" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/d5/830e9efe91a26601a2bebde6f299239d2d26e542f5d4b3bc7e8c23c81a3f/types_s3transfer-0.12.0.tar.gz", hash = "sha256:f8f59201481e904362873bf0be3267f259d60ad946ebdfcb847d092a1fa26f98", size = 14096 } +sdist = { url = "https://files.pythonhosted.org/packages/79/66/1b276526aad4696a9519919e637801f2c103419d2c248a6feb2729e034d1/types_setuptools-80.9.0.20250529.tar.gz", hash = "sha256:79e088ba0cba2186c8d6499cbd3e143abb142d28a44b042c28d3148b1e353c91", size = 41337 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/43/6097275152463ac9bacf1e00aab30bc6682bf45f6a031be8bf029c030ba2/types_s3transfer-0.12.0-py3-none-any.whl", hash = "sha256:101bbc5b7f00b71512374df881f480fc6bf63c948b5098ab024bf3370fbfb0e8", size = 19553 }, + { url = "https://files.pythonhosted.org/packages/1b/d8/83790d67ec771bf029a45ff1bd1aedbb738d8aa58c09dd0cc3033eea0e69/types_setuptools-80.9.0.20250529-py3-none-any.whl", hash = "sha256:00dfcedd73e333a430e10db096e4d46af93faf9314f832f13b6bbe3d6757e95f", size = 63263 }, ] [[package]] @@ -5953,37 +5946,37 @@ wheels = [ [[package]] name = "types-six" -version = "1.17.0.20250403" +version = "1.17.0.20250515" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/78/a711162eca091781522be07bf10694f2b731bbdbb885ec037a807e7658c5/types_six-1.17.0.20250403.tar.gz", hash = "sha256:82076f86e6e672a95adbf8b52625b1b3c72a8b9a893180344c1a02a6daabead6", size = 15521 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/78/344047eeced8d230140aa3d9503aa969acb61c6095e7308bbc1ff1de3865/types_six-1.17.0.20250515.tar.gz", hash = "sha256:f4f7f0398cb79304e88397336e642b15e96fbeacf5b96d7625da366b069d2d18", size = 15598 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/d1/14a6a959a3f53105034ebe346a1f3c375296637292780f6e952fcf634974/types_six-1.17.0.20250403-py3-none-any.whl", hash = "sha256:0bbb20fc34a18163afe7cac70b85864bd6937e6d73413c5b8f424def28760ae8", size = 19951 }, + { url = "https://files.pythonhosted.org/packages/d1/85/5ee1c8e35b33b9c8ea1816d5a4e119c27f8bb1539b73b1f636f07aa64750/types_six-1.17.0.20250515-py3-none-any.whl", hash = "sha256:adfaa9568caf35e03d80ffa4ed765c33b282579c869b40bf4b6009c7d8db3fb1", size = 19987 }, ] [[package]] name = "types-tensorflow" -version = "2.18.0.20250506" +version = "2.18.0.20250516" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "types-protobuf" }, { name = "types-requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cd/b4/f5ec306fe6f678e7f1e0beec6aa5065dfa0a3442c0791c2d1d9f6ed10010/types_tensorflow-2.18.0.20250506.tar.gz", hash = "sha256:bf366668592982af33ddec16efa07dfcc57cab9129b98f1acb8c3ad4908bc4e6", size = 257733 } +sdist = { url = "https://files.pythonhosted.org/packages/4b/18/b726d886e7af565c4439d2c8d32e510651be40807e2a66aaea2ed75d7c82/types_tensorflow-2.18.0.20250516.tar.gz", hash = "sha256:5777e1848e52b1f4a87b44ce1ec738b7407a744669bab87ec0f5f1e0ce6bd1fe", size = 257705 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/bd/11dcefa1d7fc157dab409b2f511ff9cb2d17715d6297f8be22abe19d64ef/types_tensorflow-2.18.0.20250506-py3-none-any.whl", hash = "sha256:b4f326f692e5d20f90e0a9899361b6327aa2c88af0d6a9c49490d8136e5ccec2", size = 329285 }, + { url = "https://files.pythonhosted.org/packages/96/fd/0d8fbc7172fa7cca345c61a949952df8906f6da161dfbb4305c670aeabad/types_tensorflow-2.18.0.20250516-py3-none-any.whl", hash = "sha256:e8681f8c2a60f87f562df1472790c1e930895e7e463c4c65d1be98d8d908e45e", size = 329211 }, ] [[package]] name = "types-tqdm" -version = "4.67.0.20250513" +version = "4.67.0.20250516" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/74/a77b5179e3543853c51ce786b300cd253934477c81aab4d786dff9894724/types_tqdm-4.67.0.20250513.tar.gz", hash = "sha256:907028c8d0a8fc20072132cd0cee72a3b6c72abf32f5ff914a7749e7d13b351e", size = 17207 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/07/eb40de2dc2ff2d1a53180330981b1bdb42313ab4e1b11195d8d64c878b3c/types_tqdm-4.67.0.20250516.tar.gz", hash = "sha256:230ccab8a332d34f193fc007eb132a6ef54b4512452e718bf21ae0a7caeb5a6b", size = 17232 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/7b/996a534691afd516f60fa3ad3f4101b38f7222fff6c1b12f508a4c817695/types_tqdm-4.67.0.20250513-py3-none-any.whl", hash = "sha256:73d2bdac28bab49235d8660aece6c415636a0fb406f7a24b39737dfc6bf6a5dd", size = 24060 }, + { url = "https://files.pythonhosted.org/packages/3b/92/df621429f098fc573a63a8ba348e731c3051b397df0cff278f8887f28d24/types_tqdm-4.67.0.20250516-py3-none-any.whl", hash = "sha256:1dd9b2c65273f2342f37e5179bc6982df86b6669b3376efc12aef0a29e35d36d", size = 24032 }, ] [[package]] @@ -5997,11 +5990,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.13.2" +version = "4.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 } +sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 }, + { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839 }, ] [[package]] @@ -6019,14 +6012,14 @@ wheels = [ [[package]] name = "typing-inspection" -version = "0.4.0" +version = "0.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726 } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125 }, + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552 }, ] [[package]] @@ -6129,22 +6122,20 @@ pptx = [ [[package]] name = "unstructured-client" -version = "0.34.0" +version = "0.36.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiofiles" }, { name = "cryptography" }, - { name = "eval-type-backport" }, { name = "httpx" }, { name = "nest-asyncio" }, { name = "pydantic" }, { name = "pypdf" }, { name = "requests-toolbelt" }, - { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ac/32/9e819deaa5a59b57d97055b6c2cb9a83494e2f9c0fb07f56b3030bd1490f/unstructured_client-0.34.0.tar.gz", hash = "sha256:bc1c34edc622545993f1061127996da2576fc602fefd23e5cd8454e04c421e1f", size = 81006 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/4d/d829dbef1138251de771cd52b277d93fb1c4e79d56be3e44e6d2ce76bd62/unstructured_client-0.36.0.tar.gz", hash = "sha256:ab293498100275c0e1d74c926c82dae2b3ba3fbb88945c0ba03b4b7a29197e4a", size = 86010 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/e3/d1c2d02d953555d2830af3013d5ce76351507441f148f81469ae751bec7c/unstructured_client-0.34.0-py3-none-any.whl", hash = "sha256:3180d2030695fe6279e7f6f3a1fb92b4038f26c5706e6f9dfe063f816893b734", size = 189417 }, + { url = "https://files.pythonhosted.org/packages/b9/4a/ae162e583bbdd0996f92ad18871a737d710260d8c0cfd78f1be6aa0ac150/unstructured_client-0.36.0-py3-none-any.whl", hash = "sha256:d0ecf3ac4d481437d858147904ff6e41205032cf8353af5cdd3ebaa190481d6a", size = 195765 }, ] [[package]] @@ -6161,11 +6152,11 @@ wheels = [ [[package]] name = "uritemplate" -version = "4.1.1" +version = "4.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d2/5a/4742fdba39cd02a56226815abfa72fe0aa81c33bed16ed045647d6000eba/uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0", size = 273898 } +sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c0/7461b49cd25aeece13766f02ee576d1db528f1c37ce69aee300e075b485b/uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e", size = 10356 }, + { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488 }, ] [[package]] @@ -6179,22 +6170,23 @@ wheels = [ [[package]] name = "uuid-utils" -version = "0.10.0" +version = "0.11.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/0a/cbdb2eb4845dafeb632d02a18f47b02f87f2ce4f25266f5e3c017976ce89/uuid_utils-0.10.0.tar.gz", hash = "sha256:5db0e1890e8f008657ffe6ded4d9459af724ab114cfe82af1557c87545301539", size = 18828 } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/7d83b937889d65682d95b40c94ba226b353d3f532290ee3acb17c8746e49/uuid_utils-0.11.0.tar.gz", hash = "sha256:18cf2b7083da7f3cca0517647213129eb16d20d7ed0dd74b3f4f8bff2aa334ea", size = 18854 } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/54/9d22fa16b19e5d1676eba510f08a9c458d96e2a62ff2c8ebad64251afb18/uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d5a4508feefec62456cd6a41bcdde458d56827d908f226803b886d22a3d5e63", size = 573006 }, - { url = "https://files.pythonhosted.org/packages/08/8e/f895c6e52aa603e521fbc13b8626ba5dd99b6e2f5a55aa96ba5b232f4c53/uuid_utils-0.10.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:dbefc2b9113f9dfe56bdae58301a2b3c53792221410d422826f3d1e3e6555fe7", size = 292543 }, - { url = "https://files.pythonhosted.org/packages/b6/58/cc4834f377a5e97d6e184408ad96d13042308de56643b6e24afe1f6f34df/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffc49c33edf87d1ec8112a9b43e4cf55326877716f929c165a2cc307d31c73d5", size = 323340 }, - { url = "https://files.pythonhosted.org/packages/37/e3/6aeddf148f6a7dd7759621b000e8c85382ec83f52ae79b60842d1dc3ab6b/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0636b6208f69d5a4e629707ad2a89a04dfa8d1023e1999181f6830646ca048a1", size = 329653 }, - { url = "https://files.pythonhosted.org/packages/0c/00/dd6c2164ace70b7b1671d9129267df331481d7d1e5f9c5e6a564f07953f6/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bc06452856b724df9dedfc161c3582199547da54aeb81915ec2ed54f92d19b0", size = 365471 }, - { url = "https://files.pythonhosted.org/packages/b4/e7/0ab8080fcae5462a7b5e555c1cef3d63457baffb97a59b9bc7b005a3ecb1/uuid_utils-0.10.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:263b2589111c61decdd74a762e8f850c9e4386fb78d2cf7cb4dfc537054cda1b", size = 325844 }, - { url = "https://files.pythonhosted.org/packages/73/39/52d94e9ef75b03f44b39ffc6ac3167e93e74ef4d010a93d25589d9f48540/uuid_utils-0.10.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a558db48b7096de6b4d2d2210d82bba8586a6d55f99106b03bb7d01dc5c5bcd6", size = 344389 }, - { url = "https://files.pythonhosted.org/packages/7c/29/4824566f62666238290d99c62a58e4ab2a8b9cf2eccf94cebd9b3359131e/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:807465067f3c892514230326ac71a79b28a8dfe2c88ecd2d5675fc844f3c76b5", size = 510078 }, - { url = "https://files.pythonhosted.org/packages/5e/8f/bbcc7130d652462c685f0d3bd26bb214b754215b476340885a4cb50fb89a/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:57423d4a2b9d7b916de6dbd75ba85465a28f9578a89a97f7d3e098d9aa4e5d4a", size = 515937 }, - { url = "https://files.pythonhosted.org/packages/23/f8/34e0c00f5f188604d336713e6a020fcf53b10998e8ab24735a39ab076740/uuid_utils-0.10.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:76d8d660f18ff6b767e319b1b5f927350cd92eafa4831d7ef5b57fdd1d91f974", size = 494111 }, - { url = "https://files.pythonhosted.org/packages/1a/52/b7f0066cc90a7a9c28d54061ed195cd617fde822e5d6ac3ccc88509c3c44/uuid_utils-0.10.0-cp39-abi3-win32.whl", hash = "sha256:6c11a71489338837db0b902b75e1ba7618d5d29f05fde4f68b3f909177dbc226", size = 173520 }, - { url = "https://files.pythonhosted.org/packages/8b/15/f04f58094674d333974243fb45d2c740cf4b79186fb707168e57943c84a3/uuid_utils-0.10.0-cp39-abi3-win_amd64.whl", hash = "sha256:11c55ae64f6c0a7a0c741deae8ca2a4eaa11e9c09dbb7bec2099635696034cf7", size = 182965 }, + { url = "https://files.pythonhosted.org/packages/d2/20/4a34f2a6e77b1f0f3334b111e4d2411fc8646ab2987892a36507e2d6a498/uuid_utils-0.11.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:094445ccd323bc5507e28e9d6d86b983513efcf19ab59c2dd75239cef765631a", size = 593779 }, + { url = "https://files.pythonhosted.org/packages/a1/a1/1897cd3d37144f698392ec8aae89da2c00c6d34acd77f75312477f4510ab/uuid_utils-0.11.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6430b53d343215f85269ffd74e1d1f4b25ae1031acf0ac24ff3d5721f6a06f48", size = 300848 }, + { url = "https://files.pythonhosted.org/packages/d4/36/3ae8896de8a5320a9e7529452ed29af0082daf8c3787f17c5cbf9defc651/uuid_utils-0.11.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be2e6e4318d23195887fa74fa1d64565a34f7127fdcf22918954981d79765f68", size = 336053 }, + { url = "https://files.pythonhosted.org/packages/fe/b6/751e84cd056074a40ca9ac21db6ca4802e31d78207309c0d9c8ff69cd43b/uuid_utils-0.11.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d37289ab72aa30b5550bfa64d91431c62c89e4969bdf989988aa97f918d5f803", size = 338529 }, + { url = "https://files.pythonhosted.org/packages/3b/c2/f6a1c00a1b067a886fc57c24da46bb0bcb753c92afb898871c6df3ae606f/uuid_utils-0.11.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1012595220f945fe09641f1365a8a06915bf432cac1b31ebd262944934a9b787", size = 480378 }, + { url = "https://files.pythonhosted.org/packages/60/ea/cefc0521e07a35e85416d145382ac4817957cdec037271d0c9e27cbc7d45/uuid_utils-0.11.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35cd3fc718a673e4516e87afb9325558969eca513aa734515b9031d1b651bbb1", size = 332220 }, + { url = "https://files.pythonhosted.org/packages/03/91/5929f209bd4660a7e3b4d47d26189d3cf33e14297312a5f51f5451805fec/uuid_utils-0.11.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ed325e0c40e0f59ae82b347f534df954b50cedf12bf60d025625538530e1965d", size = 359052 }, + { url = "https://files.pythonhosted.org/packages/d8/0d/32034d5b13bc07dd95f23122cb743b4eeca8e6d88173ea3c7100c67b6269/uuid_utils-0.11.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5c8b7cf201990ee3140956e541967bd556a7365ec738cb504b04187ad89c757a", size = 515186 }, + { url = "https://files.pythonhosted.org/packages/e7/43/ccf2474f723d6de5e214c22999ffb34219acf83d1e3fff6a4734172e10c0/uuid_utils-0.11.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:9966df55bed5d538ba2e9cc40115796480f437f9007727116ef99dc2f42bd5fa", size = 535318 }, + { url = "https://files.pythonhosted.org/packages/fb/05/f668b4ad2b3542cd021c4b27d1ff4e425f854f299bcf7ee36f304399a58c/uuid_utils-0.11.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb04b6c604968424b7e6398d54debbdd5b771b39fc1e648c6eabf3f1dc20582e", size = 502691 }, + { url = "https://files.pythonhosted.org/packages/9e/0b/b906301638eef837c89b19206989dbe27794c591d794ecc06167d9a47c41/uuid_utils-0.11.0-cp39-abi3-win32.whl", hash = "sha256:18420eb3316bb514f09f2da15750ac135478c3a12a704e2c5fb59eab642bb255", size = 180147 }, + { url = "https://files.pythonhosted.org/packages/56/99/ad24ee5ecfc5fbd4a4490bb59c0e72ce604d5eef08683d345546ff6a6f2d/uuid_utils-0.11.0-cp39-abi3-win_amd64.whl", hash = "sha256:37c4805af61a7cce899597d34e7c3dd5cb6a8b4b93a90fbca3826b071ba544df", size = 183574 }, + { url = "https://files.pythonhosted.org/packages/0e/76/2301b1d34defc8c234596ffb6e6d456cd7ef061d108e10a14ceda5ec5d4b/uuid_utils-0.11.0-cp39-abi3-win_arm64.whl", hash = "sha256:4065cf17bbe97f6d8ccc7dc6a0bae7d28fd4797d7f32028a5abd979aeb7bf7c9", size = 181014 }, ] [[package]] @@ -6208,15 +6200,15 @@ wheels = [ [[package]] name = "uvicorn" -version = "0.34.2" +version = "0.34.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815 } +sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483 }, + { url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431 }, ] [package.optional-dependencies] @@ -6367,9 +6359,10 @@ wheels = [ [[package]] name = "weave" -version = "0.51.46" +version = "0.51.50" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "click" }, { name = "diskcache" }, { name = "emoji" }, { name = "gql", extra = ["aiohttp", "requests"] }, @@ -6383,9 +6376,9 @@ dependencies = [ { name = "uuid-utils" }, { name = "wandb" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/08/4f7cf06bd01eb2f95cebfcf402972ce1b16f13051f712aee96c54de0631f/weave-0.51.46.tar.gz", hash = "sha256:014b25c1aa1a3d402aebad6bd173c2eab0be9ab526903494734e4566bf064dde", size = 394578 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/d1/47ab7923eb389ec7b1ca0138d9929dc50bfd0dfac324f42167f99fa02798/weave-0.51.50.tar.gz", hash = "sha256:773434765a3230bf8f4dfe9e04f9c7dfd90b03f18bb5e069186ce67d1f7c4dd8", size = 410739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/70/2e/c15f7b2ac26a0242d700f62e2f7ab247569e5c18c9375a0d54d3f13f9019/weave-0.51.46-py3-none-any.whl", hash = "sha256:a2168e5b241af1b46309309c993af498ec87b6021b566271c2d8ac7b89b9bb6a", size = 503946 }, + { url = "https://files.pythonhosted.org/packages/e4/4a/72ed6f8435759f44090c8ae81d3a50716f0c3e527e733a78e77b9a834372/weave-0.51.50-py3-none-any.whl", hash = "sha256:23fb74ec95f57fe30f31019f32f6626f39993aa228024eb9cf8fe83e58b698de", size = 524057 }, ] [[package]] @@ -6422,33 +6415,33 @@ wheels = [ [[package]] name = "websockets" -version = "14.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/54/8359678c726243d19fae38ca14a334e740782336c9f19700858c4eb64a1e/websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5", size = 164394 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/b6/504695fb9a33df0ca56d157f5985660b5fc5b4bf8c78f121578d2d653392/websockets-14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3bdc8c692c866ce5fefcaf07d2b55c91d6922ac397e031ef9b774e5b9ea42166", size = 163088 }, - { url = "https://files.pythonhosted.org/packages/81/26/ebfb8f6abe963c795122439c6433c4ae1e061aaedfc7eff32d09394afbae/websockets-14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c93215fac5dadc63e51bcc6dceca72e72267c11def401d6668622b47675b097f", size = 160745 }, - { url = "https://files.pythonhosted.org/packages/a1/c6/1435ad6f6dcbff80bb95e8986704c3174da8866ddb751184046f5c139ef6/websockets-14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c9b6535c0e2cf8a6bf938064fb754aaceb1e6a4a51a80d884cd5db569886910", size = 160995 }, - { url = "https://files.pythonhosted.org/packages/96/63/900c27cfe8be1a1f2433fc77cd46771cf26ba57e6bdc7cf9e63644a61863/websockets-14.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a52a6d7cf6938e04e9dceb949d35fbdf58ac14deea26e685ab6368e73744e4c", size = 170543 }, - { url = "https://files.pythonhosted.org/packages/00/8b/bec2bdba92af0762d42d4410593c1d7d28e9bfd952c97a3729df603dc6ea/websockets-14.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f05702e93203a6ff5226e21d9b40c037761b2cfb637187c9802c10f58e40473", size = 169546 }, - { url = "https://files.pythonhosted.org/packages/6b/a9/37531cb5b994f12a57dec3da2200ef7aadffef82d888a4c29a0d781568e4/websockets-14.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22441c81a6748a53bfcb98951d58d1af0661ab47a536af08920d129b4d1c3473", size = 169911 }, - { url = "https://files.pythonhosted.org/packages/60/d5/a6eadba2ed9f7e65d677fec539ab14a9b83de2b484ab5fe15d3d6d208c28/websockets-14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd9b868d78b194790e6236d9cbc46d68aba4b75b22497eb4ab64fa640c3af56", size = 170183 }, - { url = "https://files.pythonhosted.org/packages/76/57/a338ccb00d1df881c1d1ee1f2a20c9c1b5b29b51e9e0191ee515d254fea6/websockets-14.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a5a20d5843886d34ff8c57424cc65a1deda4375729cbca4cb6b3353f3ce4142", size = 169623 }, - { url = "https://files.pythonhosted.org/packages/64/22/e5f7c33db0cb2c1d03b79fd60d189a1da044e2661f5fd01d629451e1db89/websockets-14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:34277a29f5303d54ec6468fb525d99c99938607bc96b8d72d675dee2b9f5bf1d", size = 169583 }, - { url = "https://files.pythonhosted.org/packages/aa/2e/2b4662237060063a22e5fc40d46300a07142afe30302b634b4eebd717c07/websockets-14.2-cp311-cp311-win32.whl", hash = "sha256:02687db35dbc7d25fd541a602b5f8e451a238ffa033030b172ff86a93cb5dc2a", size = 163969 }, - { url = "https://files.pythonhosted.org/packages/94/a5/0cda64e1851e73fc1ecdae6f42487babb06e55cb2f0dc8904b81d8ef6857/websockets-14.2-cp311-cp311-win_amd64.whl", hash = "sha256:862e9967b46c07d4dcd2532e9e8e3c2825e004ffbf91a5ef9dde519ee2effb0b", size = 164408 }, - { url = "https://files.pythonhosted.org/packages/c1/81/04f7a397653dc8bec94ddc071f34833e8b99b13ef1a3804c149d59f92c18/websockets-14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1f20522e624d7ffbdbe259c6b6a65d73c895045f76a93719aa10cd93b3de100c", size = 163096 }, - { url = "https://files.pythonhosted.org/packages/ec/c5/de30e88557e4d70988ed4d2eabd73fd3e1e52456b9f3a4e9564d86353b6d/websockets-14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:647b573f7d3ada919fd60e64d533409a79dcf1ea21daeb4542d1d996519ca967", size = 160758 }, - { url = "https://files.pythonhosted.org/packages/e5/8c/d130d668781f2c77d106c007b6c6c1d9db68239107c41ba109f09e6c218a/websockets-14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6af99a38e49f66be5a64b1e890208ad026cda49355661549c507152113049990", size = 160995 }, - { url = "https://files.pythonhosted.org/packages/a6/bc/f6678a0ff17246df4f06765e22fc9d98d1b11a258cc50c5968b33d6742a1/websockets-14.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:091ab63dfc8cea748cc22c1db2814eadb77ccbf82829bac6b2fbe3401d548eda", size = 170815 }, - { url = "https://files.pythonhosted.org/packages/d8/b2/8070cb970c2e4122a6ef38bc5b203415fd46460e025652e1ee3f2f43a9a3/websockets-14.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b374e8953ad477d17e4851cdc66d83fdc2db88d9e73abf755c94510ebddceb95", size = 169759 }, - { url = "https://files.pythonhosted.org/packages/81/da/72f7caabd94652e6eb7e92ed2d3da818626e70b4f2b15a854ef60bf501ec/websockets-14.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a39d7eceeea35db85b85e1169011bb4321c32e673920ae9c1b6e0978590012a3", size = 170178 }, - { url = "https://files.pythonhosted.org/packages/31/e0/812725b6deca8afd3a08a2e81b3c4c120c17f68c9b84522a520b816cda58/websockets-14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a6f3efd47ffd0d12080594f434faf1cd2549b31e54870b8470b28cc1d3817d9", size = 170453 }, - { url = "https://files.pythonhosted.org/packages/66/d3/8275dbc231e5ba9bb0c4f93144394b4194402a7a0c8ffaca5307a58ab5e3/websockets-14.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:065ce275e7c4ffb42cb738dd6b20726ac26ac9ad0a2a48e33ca632351a737267", size = 169830 }, - { url = "https://files.pythonhosted.org/packages/a3/ae/e7d1a56755ae15ad5a94e80dd490ad09e345365199600b2629b18ee37bc7/websockets-14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e9d0e53530ba7b8b5e389c02282f9d2aa47581514bd6049d3a7cffe1385cf5fe", size = 169824 }, - { url = "https://files.pythonhosted.org/packages/b6/32/88ccdd63cb261e77b882e706108d072e4f1c839ed723bf91a3e1f216bf60/websockets-14.2-cp312-cp312-win32.whl", hash = "sha256:20e6dd0984d7ca3037afcb4494e48c74ffb51e8013cac71cf607fffe11df7205", size = 163981 }, - { url = "https://files.pythonhosted.org/packages/b3/7d/32cdb77990b3bdc34a306e0a0f73a1275221e9a66d869f6ff833c95b56ef/websockets-14.2-cp312-cp312-win_amd64.whl", hash = "sha256:44bba1a956c2c9d268bdcdf234d5e5ff4c9b6dc3e300545cbe99af59dda9dcce", size = 164421 }, - { url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416 }, +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423 }, + { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082 }, + { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330 }, + { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878 }, + { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883 }, + { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252 }, + { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521 }, + { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958 }, + { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918 }, + { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388 }, + { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828 }, + { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437 }, + { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096 }, + { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332 }, + { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152 }, + { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096 }, + { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523 }, + { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790 }, + { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165 }, + { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160 }, + { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395 }, + { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841 }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 }, ] [[package]] @@ -6592,11 +6585,11 @@ wheels = [ [[package]] name = "zipp" -version = "3.21.0" +version = "3.22.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/50/bad581df71744867e9468ebd0bcd6505de3b275e06f202c2cb016e3ff56f/zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4", size = 24545 } +sdist = { url = "https://files.pythonhosted.org/packages/12/b6/7b3d16792fdf94f146bed92be90b4eb4563569eca91513c8609aebf0c167/zipp-3.22.0.tar.gz", hash = "sha256:dd2f28c3ce4bc67507bfd3781d21b7bb2be31103b51a4553ad7d90b84e57ace5", size = 25257 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/1a/7e4798e9339adc931158c9d69ecc34f5e6791489d469f5e50ec15e35f458/zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931", size = 9630 }, + { url = "https://files.pythonhosted.org/packages/ad/da/f64669af4cae46f17b90798a827519ce3737d31dbafad65d391e49643dc4/zipp-3.22.0-py3-none-any.whl", hash = "sha256:fe208f65f2aca48b81f9e6fd8cf7b8b32c26375266b009b413d45306b6148343", size = 9796 }, ] [[package]] From 257bf13fef619a06c6ec24c3226af3a921c30453 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 3 Jun 2025 16:36:10 +0800 Subject: [PATCH 39/73] refactor: Removes unused LLMMode value_of method (#20575) Signed-off-by: -LAN- --- .../easy_ui_based_app/model_config/converter.py | 2 +- api/core/model_runtime/entities/llm_entities.py | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/api/core/app/app_config/easy_ui_based_app/model_config/converter.py b/api/core/app/app_config/easy_ui_based_app/model_config/converter.py index 5beb09c2aa..5b5eefe315 100644 --- a/api/core/app/app_config/easy_ui_based_app/model_config/converter.py +++ b/api/core/app/app_config/easy_ui_based_app/model_config/converter.py @@ -70,7 +70,7 @@ class ModelConfigConverter: if not model_mode: model_mode = LLMMode.CHAT.value if model_schema and model_schema.model_properties.get(ModelPropertyKey.MODE): - model_mode = LLMMode.value_of(model_schema.model_properties[ModelPropertyKey.MODE]).value + model_mode = LLMMode(model_schema.model_properties[ModelPropertyKey.MODE]).value if not model_schema: raise ValueError(f"Model {model_name} not exist.") diff --git a/api/core/model_runtime/entities/llm_entities.py b/api/core/model_runtime/entities/llm_entities.py index 9bb118622b..de5a748d4f 100644 --- a/api/core/model_runtime/entities/llm_entities.py +++ b/api/core/model_runtime/entities/llm_entities.py @@ -17,19 +17,6 @@ class LLMMode(StrEnum): COMPLETION = "completion" CHAT = "chat" - @classmethod - def value_of(cls, value: str) -> "LLMMode": - """ - Get value of given mode. - - :param value: mode value - :return: mode - """ - for mode in cls: - if mode.value == value: - return mode - raise ValueError(f"invalid mode value {value}") - class LLMUsage(ModelUsage): """ From 36f1b4b222a7b9ae85a25df26910b18bcdd9e141 Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 3 Jun 2025 16:36:18 +0800 Subject: [PATCH 40/73] fix: Ensure model config integrity in retrieval processes (#20576) Signed-off-by: -LAN- --- .../knowledge_retrieval_node.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py b/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py index 53124f962a..01666b9a46 100644 --- a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py +++ b/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py @@ -175,7 +175,9 @@ class KnowledgeRetrievalNode(LLMNode): dataset_retrieval = DatasetRetrieval() if node_data.retrieval_mode == DatasetRetrieveConfigEntity.RetrieveStrategy.SINGLE.value: # fetch model config - model_instance, model_config = self._fetch_model_config(node_data.single_retrieval_config.model) # type: ignore + if node_data.single_retrieval_config is None: + raise ValueError("single_retrieval_config is required") + model_instance, model_config = self.get_model_config(node_data.single_retrieval_config.model) # check model is support tool calling model_type_instance = model_config.provider_model_bundle.model_type_instance model_type_instance = cast(LargeLanguageModel, model_type_instance) @@ -426,7 +428,7 @@ class KnowledgeRetrievalNode(LLMNode): raise ValueError("metadata_model_config is required") # get metadata model instance # fetch model config - model_instance, model_config = self._fetch_model_config(node_data.metadata_model_config) # type: ignore + model_instance, model_config = self.get_model_config(metadata_model_config) # fetch prompt messages prompt_template = self._get_prompt_template( node_data=node_data, @@ -552,14 +554,7 @@ class KnowledgeRetrievalNode(LLMNode): variable_mapping[node_id + ".query"] = node_data.query_variable_selector return variable_mapping - def _fetch_model_config(self, model: ModelConfig) -> tuple[ModelInstance, ModelConfigWithCredentialsEntity]: # type: ignore - """ - Fetch model config - :param model: model - :return: - """ - if model is None: - raise ValueError("model is required") + def get_model_config(self, model: ModelConfig) -> tuple[ModelInstance, ModelConfigWithCredentialsEntity]: model_name = model.name provider_name = model.provider From e40e9db39ab2a004cbde97004f619573b19be91b Mon Sep 17 00:00:00 2001 From: Anshuman Saini <90978443+AnshumanSaini@users.noreply.github.com> Date: Tue, 3 Jun 2025 14:08:48 +0530 Subject: [PATCH 41/73] fixes #19634 (#20545) --- api/libs/smtp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/libs/smtp.py b/api/libs/smtp.py index 2325d69a41..35561f071c 100644 --- a/api/libs/smtp.py +++ b/api/libs/smtp.py @@ -28,7 +28,8 @@ class SMTPClient: else: smtp = smtplib.SMTP(self.server, self.port, timeout=10) - if self.username and self.password: + # Only authenticate if both username and password are non-empty + if self.username and self.password and self.username.strip() and self.password.strip(): smtp.login(self.username, self.password) msg = MIMEMultipart() From 157d916154a87ebc1549affe3c5a1f478f85fcac Mon Sep 17 00:00:00 2001 From: Muttakin Islam Hasib Date: Tue, 3 Jun 2025 14:46:57 +0600 Subject: [PATCH 42/73] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(middleware)?= =?UTF-8?q?:=20remove=20duplicate=20CSP=20header=20assignment=20(#20548)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/middleware.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/middleware.ts b/web/middleware.ts index 3fee535ea4..33bdb97481 100644 --- a/web/middleware.ts +++ b/web/middleware.ts @@ -56,11 +56,6 @@ export function middleware(request: NextRequest) { contentSecurityPolicyHeaderValue, ) - response.headers.set( - 'Content-Security-Policy', - contentSecurityPolicyHeaderValue, - ) - return wrapResponseWithXFrameOptions(response, pathname) } From 888cd86afda7be6c84fffd6bd1dd93883ea2cea8 Mon Sep 17 00:00:00 2001 From: Bowen Liang Date: Tue, 3 Jun 2025 17:01:35 +0800 Subject: [PATCH 43/73] chore: prepare the plugin daemon base url to yarl URL ahead intstead of in every invocation (#20541) --- api/core/helper/code_executor/code_executor.py | 3 ++- api/core/helper/marketplace.py | 15 +++++++-------- api/core/plugin/impl/base.py | 7 +++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/api/core/helper/code_executor/code_executor.py b/api/core/helper/code_executor/code_executor.py index 5bb045cce9..2b580cb373 100644 --- a/api/core/helper/code_executor/code_executor.py +++ b/api/core/helper/code_executor/code_executor.py @@ -15,6 +15,7 @@ from core.helper.code_executor.python3.python3_transformer import Python3Templat from core.helper.code_executor.template_transformer import TemplateTransformer logger = logging.getLogger(__name__) +code_execution_endpoint_url = URL(str(dify_config.CODE_EXECUTION_ENDPOINT)) class CodeExecutionError(Exception): @@ -64,7 +65,7 @@ class CodeExecutor: :param code: code :return: """ - url = URL(str(dify_config.CODE_EXECUTION_ENDPOINT)) / "v1" / "sandbox" / "run" + url = code_execution_endpoint_url / "v1" / "sandbox" / "run" headers = {"X-Api-Key": dify_config.CODE_EXECUTION_API_KEY} diff --git a/api/core/helper/marketplace.py b/api/core/helper/marketplace.py index f4129b88ed..65bf4fc1db 100644 --- a/api/core/helper/marketplace.py +++ b/api/core/helper/marketplace.py @@ -7,29 +7,28 @@ from configs import dify_config from core.helper.download import download_with_size_limit from core.plugin.entities.marketplace import MarketplacePluginDeclaration +marketplace_api_url = URL(str(dify_config.MARKETPLACE_API_URL)) -def get_plugin_pkg_url(plugin_unique_identifier: str): - return (URL(str(dify_config.MARKETPLACE_API_URL)) / "api/v1/plugins/download").with_query( - unique_identifier=plugin_unique_identifier - ) + +def get_plugin_pkg_url(plugin_unique_identifier: str) -> str: + return str((marketplace_api_url / "api/v1/plugins/download").with_query(unique_identifier=plugin_unique_identifier)) def download_plugin_pkg(plugin_unique_identifier: str): - url = str(get_plugin_pkg_url(plugin_unique_identifier)) - return download_with_size_limit(url, dify_config.PLUGIN_MAX_PACKAGE_SIZE) + return download_with_size_limit(get_plugin_pkg_url(plugin_unique_identifier), dify_config.PLUGIN_MAX_PACKAGE_SIZE) def batch_fetch_plugin_manifests(plugin_ids: list[str]) -> Sequence[MarketplacePluginDeclaration]: if len(plugin_ids) == 0: return [] - url = str(URL(str(dify_config.MARKETPLACE_API_URL)) / "api/v1/plugins/batch") + url = str(marketplace_api_url / "api/v1/plugins/batch") response = requests.post(url, json={"plugin_ids": plugin_ids}) response.raise_for_status() return [MarketplacePluginDeclaration(**plugin) for plugin in response.json()["data"]["plugins"]] def record_install_plugin_event(plugin_unique_identifier: str): - url = str(URL(str(dify_config.MARKETPLACE_API_URL)) / "api/v1/stats/plugins/install_count") + url = str(marketplace_api_url / "api/v1/stats/plugins/install_count") response = requests.post(url, json={"unique_identifier": plugin_unique_identifier}) response.raise_for_status() diff --git a/api/core/plugin/impl/base.py b/api/core/plugin/impl/base.py index 7b9592bff3..7375726fa9 100644 --- a/api/core/plugin/impl/base.py +++ b/api/core/plugin/impl/base.py @@ -31,8 +31,7 @@ from core.plugin.impl.exc import ( PluginUniqueIdentifierError, ) -plugin_daemon_inner_api_baseurl = dify_config.PLUGIN_DAEMON_URL -plugin_daemon_inner_api_key = dify_config.PLUGIN_DAEMON_KEY +plugin_daemon_inner_api_baseurl = URL(str(dify_config.PLUGIN_DAEMON_URL)) T = TypeVar("T", bound=(BaseModel | dict | list | bool | str)) @@ -53,9 +52,9 @@ class BasePluginClient: """ Make a request to the plugin daemon inner API. """ - url = URL(str(plugin_daemon_inner_api_baseurl)) / path + url = plugin_daemon_inner_api_baseurl / path headers = headers or {} - headers["X-Api-Key"] = plugin_daemon_inner_api_key + headers["X-Api-Key"] = dify_config.PLUGIN_DAEMON_KEY headers["Accept-Encoding"] = "gzip, deflate, br" if headers.get("Content-Type") == "application/json" and isinstance(data, dict): From 25be7c1ad50cde49ccd78dd800fdcf1fe7ab4593 Mon Sep 17 00:00:00 2001 From: crazywoola <100913391+crazywoola@users.noreply.github.com> Date: Tue, 3 Jun 2025 17:43:48 +0800 Subject: [PATCH 44/73] =?UTF-8?q?Revert=20"=E2=99=BB=EF=B8=8F=20refactor(m?= =?UTF-8?q?iddleware):=20remove=20duplicate=20CSP=20header=20assignment"?= =?UTF-8?q?=20(#20592)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/middleware.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/middleware.ts b/web/middleware.ts index 33bdb97481..3fee535ea4 100644 --- a/web/middleware.ts +++ b/web/middleware.ts @@ -56,6 +56,11 @@ export function middleware(request: NextRequest) { contentSecurityPolicyHeaderValue, ) + response.headers.set( + 'Content-Security-Policy', + contentSecurityPolicyHeaderValue, + ) + return wrapResponseWithXFrameOptions(response, pathname) } From ca0b268ae55817706386e0a0ecefc674e66b366f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?= Date: Tue, 3 Jun 2025 18:17:34 +0800 Subject: [PATCH 45/73] fix: variable aggregator with group and file raise exception (#20581) --- api/core/workflow/nodes/variable_aggregator/entities.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/core/workflow/nodes/variable_aggregator/entities.py b/api/core/workflow/nodes/variable_aggregator/entities.py index 9e58f5e944..f4577d7573 100644 --- a/api/core/workflow/nodes/variable_aggregator/entities.py +++ b/api/core/workflow/nodes/variable_aggregator/entities.py @@ -1,7 +1,8 @@ -from typing import Literal, Optional +from typing import Optional from pydantic import BaseModel +from core.variables.types import SegmentType from core.workflow.nodes.base import BaseNodeData @@ -17,7 +18,7 @@ class AdvancedSettings(BaseModel): Group. """ - output_type: Literal["string", "number", "object", "array[string]", "array[number]", "array[object]"] + output_type: SegmentType variables: list[list[str]] group_name: str From 077d6279532ba96d2dcf14eaf7f6d786e1b39b50 Mon Sep 17 00:00:00 2001 From: sayThQ199 <18852951350@163.com> Date: Tue, 3 Jun 2025 18:56:09 +0800 Subject: [PATCH 46/73] fix: ensure newlines around think tags for proper markdown rendering (#20594) --- web/app/components/base/markdown/markdown-utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/web/app/components/base/markdown/markdown-utils.ts b/web/app/components/base/markdown/markdown-utils.ts index ff7dd5db01..d77b2ddccf 100644 --- a/web/app/components/base/markdown/markdown-utils.ts +++ b/web/app/components/base/markdown/markdown-utils.ts @@ -33,5 +33,6 @@ export const preprocessThinkTag = (content: string) => { return flow([ (str: string) => str.replace(thinkOpenTagRegex, '
\n'), (str: string) => str.replace(thinkCloseTagRegex, '\n[ENDTHINKFLAG]
'), + (str: string) => str.replace(/(<\/details>)(?![^\S\r\n]*[\r\n])(?![^\S\r\n]*$)/g, '$1\n'), ])(content) } From 275e86a26c6b86409c391432a010fe0b1096b88e Mon Sep 17 00:00:00 2001 From: -LAN- Date: Tue, 3 Jun 2025 18:56:38 +0800 Subject: [PATCH 47/73] refactor: Removes tenant ID check from rate limit logic (#20585) Signed-off-by: -LAN- --- .../knowledge_retrieval_node.py | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py b/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py index 01666b9a46..5cf5848d54 100644 --- a/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py +++ b/api/core/workflow/nodes/knowledge_retrieval/knowledge_retrieval_node.py @@ -86,31 +86,31 @@ class KnowledgeRetrievalNode(LLMNode): return NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs=variables, error="Query is required." ) + # TODO(-LAN-): Move this check outside. # check rate limit - if self.tenant_id: - knowledge_rate_limit = FeatureService.get_knowledge_rate_limit(self.tenant_id) - if knowledge_rate_limit.enabled: - current_time = int(time.time() * 1000) - key = f"rate_limit_{self.tenant_id}" - redis_client.zadd(key, {current_time: current_time}) - redis_client.zremrangebyscore(key, 0, current_time - 60000) - request_count = redis_client.zcard(key) - if request_count > knowledge_rate_limit.limit: - with Session(db.engine) as session: - # add ratelimit record - rate_limit_log = RateLimitLog( - tenant_id=self.tenant_id, - subscription_plan=knowledge_rate_limit.subscription_plan, - operation="knowledge", - ) - session.add(rate_limit_log) - session.commit() - return NodeRunResult( - status=WorkflowNodeExecutionStatus.FAILED, - inputs=variables, - error="Sorry, you have reached the knowledge base request rate limit of your subscription.", - error_type="RateLimitExceeded", + knowledge_rate_limit = FeatureService.get_knowledge_rate_limit(self.tenant_id) + if knowledge_rate_limit.enabled: + current_time = int(time.time() * 1000) + key = f"rate_limit_{self.tenant_id}" + redis_client.zadd(key, {current_time: current_time}) + redis_client.zremrangebyscore(key, 0, current_time - 60000) + request_count = redis_client.zcard(key) + if request_count > knowledge_rate_limit.limit: + with Session(db.engine) as session: + # add ratelimit record + rate_limit_log = RateLimitLog( + tenant_id=self.tenant_id, + subscription_plan=knowledge_rate_limit.subscription_plan, + operation="knowledge", ) + session.add(rate_limit_log) + session.commit() + return NodeRunResult( + status=WorkflowNodeExecutionStatus.FAILED, + inputs=variables, + error="Sorry, you have reached the knowledge base request rate limit of your subscription.", + error_type="RateLimitExceeded", + ) # retrieve knowledge try: From f1c19cda7489b5dc08ec2eb74137cc6b4ca919f4 Mon Sep 17 00:00:00 2001 From: Bowen Liang Date: Wed, 4 Jun 2025 13:20:57 +0800 Subject: [PATCH 48/73] fix: unable to upload custom file in case of incorrect inffered by multiple extensions mapped from mime type with filename extension hints (#20559) --- .../components/base/file-uploader/hooks.ts | 4 +- .../base/file-uploader/utils.spec.ts | 89 +++++++++++-------- .../components/base/file-uploader/utils.ts | 31 +++++-- 3 files changed, 79 insertions(+), 45 deletions(-) diff --git a/web/app/components/base/file-uploader/hooks.ts b/web/app/components/base/file-uploader/hooks.ts index 66d5b46ba7..8e1b2148c5 100644 --- a/web/app/components/base/file-uploader/hooks.ts +++ b/web/app/components/base/file-uploader/hooks.ts @@ -231,7 +231,7 @@ export const useFile = (fileConfig: FileUpload) => { url: res.url, } if (!isAllowedFileExtension(res.name, res.mime_type, fileConfig.allowed_file_types || [], fileConfig.allowed_file_extensions || [])) { - notify({ type: 'error', message: t('common.fileUploader.fileExtensionNotSupport') }) + notify({ type: 'error', message: `${t('common.fileUploader.fileExtensionNotSupport')} ${file.type}` }) handleRemoveFile(uploadingFile.id) } if (!checkSizeLimit(newFile.supportFileType, newFile.size)) @@ -257,7 +257,7 @@ export const useFile = (fileConfig: FileUpload) => { const handleLocalFileUpload = useCallback((file: File) => { if (!isAllowedFileExtension(file.name, file.type, fileConfig.allowed_file_types || [], fileConfig.allowed_file_extensions || [])) { - notify({ type: 'error', message: t('common.fileUploader.fileExtensionNotSupport') }) + notify({ type: 'error', message: `${t('common.fileUploader.fileExtensionNotSupport')} ${file.type}` }) return } const allowedFileTypes = fileConfig.allowed_file_types diff --git a/web/app/components/base/file-uploader/utils.spec.ts b/web/app/components/base/file-uploader/utils.spec.ts index c8cf9fbe74..4a3408ef00 100644 --- a/web/app/components/base/file-uploader/utils.spec.ts +++ b/web/app/components/base/file-uploader/utils.spec.ts @@ -22,7 +22,7 @@ import { FILE_EXTS } from '../prompt-editor/constants' jest.mock('mime', () => ({ __esModule: true, default: { - getExtension: jest.fn(), + getAllExtensions: jest.fn(), }, })) @@ -58,12 +58,27 @@ describe('file-uploader utils', () => { describe('getFileExtension', () => { it('should get extension from mimetype', () => { - jest.mocked(mime.getExtension).mockReturnValue('pdf') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['pdf'])) expect(getFileExtension('file', 'application/pdf')).toBe('pdf') }) + it('should get extension from mimetype and file name 1', () => { + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['pdf'])) + expect(getFileExtension('file.pdf', 'application/pdf')).toBe('pdf') + }) + + it('should get extension from mimetype with multiple ext candidates with filename hint', () => { + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['der', 'crt', 'pem'])) + expect(getFileExtension('file.pem', 'application/x-x509-ca-cert')).toBe('pem') + }) + + it('should get extension from mimetype with multiple ext candidates without filename hint', () => { + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['der', 'crt', 'pem'])) + expect(getFileExtension('file', 'application/x-x509-ca-cert')).toBe('der') + }) + it('should get extension from filename if mimetype fails', () => { - jest.mocked(mime.getExtension).mockReturnValue(null) + jest.mocked(mime.getAllExtensions).mockReturnValue(null) expect(getFileExtension('file.txt', '')).toBe('txt') expect(getFileExtension('file.txt.docx', '')).toBe('docx') expect(getFileExtension('file', '')).toBe('') @@ -76,157 +91,157 @@ describe('file-uploader utils', () => { describe('getFileAppearanceType', () => { it('should identify gif files', () => { - jest.mocked(mime.getExtension).mockReturnValue('gif') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['gif'])) expect(getFileAppearanceType('image.gif', 'image/gif')) .toBe(FileAppearanceTypeEnum.gif) }) it('should identify image files', () => { - jest.mocked(mime.getExtension).mockReturnValue('jpg') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['jpg'])) expect(getFileAppearanceType('image.jpg', 'image/jpeg')) .toBe(FileAppearanceTypeEnum.image) - jest.mocked(mime.getExtension).mockReturnValue('jpeg') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['jpeg'])) expect(getFileAppearanceType('image.jpeg', 'image/jpeg')) .toBe(FileAppearanceTypeEnum.image) - jest.mocked(mime.getExtension).mockReturnValue('png') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['png'])) expect(getFileAppearanceType('image.png', 'image/png')) .toBe(FileAppearanceTypeEnum.image) - jest.mocked(mime.getExtension).mockReturnValue('webp') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['webp'])) expect(getFileAppearanceType('image.webp', 'image/webp')) .toBe(FileAppearanceTypeEnum.image) - jest.mocked(mime.getExtension).mockReturnValue('svg') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['svg'])) expect(getFileAppearanceType('image.svg', 'image/svgxml')) .toBe(FileAppearanceTypeEnum.image) }) it('should identify video files', () => { - jest.mocked(mime.getExtension).mockReturnValue('mp4') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['mp4'])) expect(getFileAppearanceType('video.mp4', 'video/mp4')) .toBe(FileAppearanceTypeEnum.video) - jest.mocked(mime.getExtension).mockReturnValue('mov') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['mov'])) expect(getFileAppearanceType('video.mov', 'video/quicktime')) .toBe(FileAppearanceTypeEnum.video) - jest.mocked(mime.getExtension).mockReturnValue('mpeg') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['mpeg'])) expect(getFileAppearanceType('video.mpeg', 'video/mpeg')) .toBe(FileAppearanceTypeEnum.video) - jest.mocked(mime.getExtension).mockReturnValue('webm') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['webm'])) expect(getFileAppearanceType('video.web', 'video/webm')) .toBe(FileAppearanceTypeEnum.video) }) it('should identify audio files', () => { - jest.mocked(mime.getExtension).mockReturnValue('mp3') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['mp3'])) expect(getFileAppearanceType('audio.mp3', 'audio/mpeg')) .toBe(FileAppearanceTypeEnum.audio) - jest.mocked(mime.getExtension).mockReturnValue('m4a') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['m4a'])) expect(getFileAppearanceType('audio.m4a', 'audio/mp4')) .toBe(FileAppearanceTypeEnum.audio) - jest.mocked(mime.getExtension).mockReturnValue('wav') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['wav'])) expect(getFileAppearanceType('audio.wav', 'audio/vnd.wav')) .toBe(FileAppearanceTypeEnum.audio) - jest.mocked(mime.getExtension).mockReturnValue('amr') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['amr'])) expect(getFileAppearanceType('audio.amr', 'audio/AMR')) .toBe(FileAppearanceTypeEnum.audio) - jest.mocked(mime.getExtension).mockReturnValue('mpga') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['mpga'])) expect(getFileAppearanceType('audio.mpga', 'audio/mpeg')) .toBe(FileAppearanceTypeEnum.audio) }) it('should identify code files', () => { - jest.mocked(mime.getExtension).mockReturnValue('html') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['html'])) expect(getFileAppearanceType('index.html', 'text/html')) .toBe(FileAppearanceTypeEnum.code) }) it('should identify PDF files', () => { - jest.mocked(mime.getExtension).mockReturnValue('pdf') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['pdf'])) expect(getFileAppearanceType('doc.pdf', 'application/pdf')) .toBe(FileAppearanceTypeEnum.pdf) }) it('should identify markdown files', () => { - jest.mocked(mime.getExtension).mockReturnValue('md') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['md'])) expect(getFileAppearanceType('file.md', 'text/markdown')) .toBe(FileAppearanceTypeEnum.markdown) - jest.mocked(mime.getExtension).mockReturnValue('markdown') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['markdown'])) expect(getFileAppearanceType('file.markdown', 'text/markdown')) .toBe(FileAppearanceTypeEnum.markdown) - jest.mocked(mime.getExtension).mockReturnValue('mdx') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['mdx'])) expect(getFileAppearanceType('file.mdx', 'text/mdx')) .toBe(FileAppearanceTypeEnum.markdown) }) it('should identify excel files', () => { - jest.mocked(mime.getExtension).mockReturnValue('xlsx') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['xlsx'])) expect(getFileAppearanceType('doc.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')) .toBe(FileAppearanceTypeEnum.excel) - jest.mocked(mime.getExtension).mockReturnValue('xls') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['xls'])) expect(getFileAppearanceType('doc.xls', 'application/vnd.ms-excel')) .toBe(FileAppearanceTypeEnum.excel) }) it('should identify word files', () => { - jest.mocked(mime.getExtension).mockReturnValue('doc') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['doc'])) expect(getFileAppearanceType('doc.doc', 'application/msword')) .toBe(FileAppearanceTypeEnum.word) - jest.mocked(mime.getExtension).mockReturnValue('docx') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['docx'])) expect(getFileAppearanceType('doc.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')) .toBe(FileAppearanceTypeEnum.word) }) it('should identify word files', () => { - jest.mocked(mime.getExtension).mockReturnValue('ppt') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['ppt'])) expect(getFileAppearanceType('doc.ppt', 'application/vnd.ms-powerpoint')) .toBe(FileAppearanceTypeEnum.ppt) - jest.mocked(mime.getExtension).mockReturnValue('pptx') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['pptx'])) expect(getFileAppearanceType('doc.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation')) .toBe(FileAppearanceTypeEnum.ppt) }) it('should identify document files', () => { - jest.mocked(mime.getExtension).mockReturnValue('txt') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['txt'])) expect(getFileAppearanceType('file.txt', 'text/plain')) .toBe(FileAppearanceTypeEnum.document) - jest.mocked(mime.getExtension).mockReturnValue('csv') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['csv'])) expect(getFileAppearanceType('file.csv', 'text/csv')) .toBe(FileAppearanceTypeEnum.document) - jest.mocked(mime.getExtension).mockReturnValue('msg') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['msg'])) expect(getFileAppearanceType('file.msg', 'application/vnd.ms-outlook')) .toBe(FileAppearanceTypeEnum.document) - jest.mocked(mime.getExtension).mockReturnValue('eml') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['eml'])) expect(getFileAppearanceType('file.eml', 'message/rfc822')) .toBe(FileAppearanceTypeEnum.document) - jest.mocked(mime.getExtension).mockReturnValue('xml') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['xml'])) expect(getFileAppearanceType('file.xml', 'application/rssxml')) .toBe(FileAppearanceTypeEnum.document) - jest.mocked(mime.getExtension).mockReturnValue('epub') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['epub'])) expect(getFileAppearanceType('file.epub', 'application/epubzip')) .toBe(FileAppearanceTypeEnum.document) }) it('should handle null mime extension', () => { - jest.mocked(mime.getExtension).mockReturnValue(null) + jest.mocked(mime.getAllExtensions).mockReturnValue(null) expect(getFileAppearanceType('file.txt', 'text/plain')) .toBe(FileAppearanceTypeEnum.document) }) @@ -360,7 +375,7 @@ describe('file-uploader utils', () => { describe('isAllowedFileExtension', () => { it('should validate allowed file extensions', () => { - jest.mocked(mime.getExtension).mockReturnValue('pdf') + jest.mocked(mime.getAllExtensions).mockReturnValue(new Set(['pdf'])) expect(isAllowedFileExtension( 'test.pdf', 'application/pdf', diff --git a/web/app/components/base/file-uploader/utils.ts b/web/app/components/base/file-uploader/utils.ts index e05c0b2087..9b5a449481 100644 --- a/web/app/components/base/file-uploader/utils.ts +++ b/web/app/components/base/file-uploader/utils.ts @@ -42,19 +42,38 @@ export const fileUpload: FileUpload = ({ }) } +const additionalExtensionMap = new Map([ + ['text/x-markdown', ['md']], +]) + export const getFileExtension = (fileName: string, fileMimetype: string, isRemote?: boolean) => { let extension = '' - if (fileMimetype) - extension = mime.getExtension(fileMimetype) || '' + let extensions = new Set() + if (fileMimetype) { + const extensionsFromMimeType = mime.getAllExtensions(fileMimetype) || new Set() + const additionalExtensions = additionalExtensionMap.get(fileMimetype) || [] + extensions = new Set([ + ...extensionsFromMimeType, + ...additionalExtensions, + ]) + } - if (fileName && !extension) { + let extensionInFileName = '' + if (fileName) { const fileNamePair = fileName.split('.') const fileNamePairLength = fileNamePair.length - if (fileNamePairLength > 1) - extension = fileNamePair[fileNamePairLength - 1] + if (fileNamePairLength > 1) { + extensionInFileName = fileNamePair[fileNamePairLength - 1].toLowerCase() + if (extensions.has(extensionInFileName)) + extension = extensionInFileName + } + } + if (!extension) { + if (extensions.size > 0) + extension = extensions.values().next().value.toLowerCase() else - extension = '' + extension = extensionInFileName } if (isRemote) From 6aba2233839108d12625b13b90634827acdcccb3 Mon Sep 17 00:00:00 2001 From: GuanMu Date: Wed, 4 Jun 2025 13:54:30 +0800 Subject: [PATCH 49/73] fix: adjust sticky header properties in Container component (#20624) --- web/app/(commonLayout)/datasets/Container.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/(commonLayout)/datasets/Container.tsx b/web/app/(commonLayout)/datasets/Container.tsx index 62569ab26b..112b6a752e 100644 --- a/web/app/(commonLayout)/datasets/Container.tsx +++ b/web/app/(commonLayout)/datasets/Container.tsx @@ -87,7 +87,7 @@ const Container = () => { return (
-
+
setActiveTab(newActiveTab)} From 4ac3600f814e3a78d568e78c8906fb52ff5cd5a1 Mon Sep 17 00:00:00 2001 From: Novice <857526207@qq.com> Date: Wed, 4 Jun 2025 13:55:00 +0800 Subject: [PATCH 50/73] fix: update app tag error (#20618) --- api/controllers/service_api/dataset/dataset.py | 1 + api/services/tag_service.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/controllers/service_api/dataset/dataset.py b/api/controllers/service_api/dataset/dataset.py index c100f53078..27e8dd3fa6 100644 --- a/api/controllers/service_api/dataset/dataset.py +++ b/api/controllers/service_api/dataset/dataset.py @@ -369,6 +369,7 @@ class DatasetTagsApi(DatasetApiResource): ) parser.add_argument("tag_id", nullable=False, required=True, help="Id of a tag.", type=str) args = parser.parse_args() + args["type"] = "knowledge" tag = TagService.update_tags(args, args.get("tag_id")) binding_count = TagService.get_tag_binding_count(args.get("tag_id")) diff --git a/api/services/tag_service.py b/api/services/tag_service.py index be748e8dd1..74c6150b44 100644 --- a/api/services/tag_service.py +++ b/api/services/tag_service.py @@ -46,6 +46,8 @@ class TagService: @staticmethod def get_tag_by_tag_name(tag_type: str, current_tenant_id: str, tag_name: str) -> list: + if not tag_type or not tag_name: + return [] tags = ( db.session.query(Tag) .filter(Tag.name == tag_name, Tag.tenant_id == current_tenant_id, Tag.type == tag_type) @@ -88,7 +90,7 @@ class TagService: @staticmethod def update_tags(args: dict, tag_id: str) -> Tag: - if TagService.get_tag_by_tag_name(args["type"], current_user.current_tenant_id, args["name"]): + if TagService.get_tag_by_tag_name(args.get("type", ""), current_user.current_tenant_id, args.get("name", "")): raise ValueError("Tag name already exists") tag = db.session.query(Tag).filter(Tag.id == tag_id).first() if not tag: From 01d500db149955ef8d2157712f7a81f735947d58 Mon Sep 17 00:00:00 2001 From: kenwoodjw Date: Wed, 4 Jun 2025 14:12:24 +0800 Subject: [PATCH 51/73] fix: autocorrect everything in web (#20605) Signed-off-by: kenwoodjw --- .../rag/datasource/keyword/jieba/stopwords.py | 12 +- .../rag/datasource/vdb/oracle/oraclevector.py | 2 +- .../datasets/template/template.ja.mdx | 38 ++--- .../datasets/template/template.zh.mdx | 32 ++--- .../answer/__mocks__/markdownContentSVG.ts | 2 +- .../develop/template/template.ja.mdx | 40 +++--- .../develop/template/template.zh.mdx | 16 +-- .../template/template_advanced_chat.ja.mdx | 50 +++---- .../template/template_advanced_chat.zh.mdx | 20 +-- .../develop/template/template_chat.ja.mdx | 52 +++---- .../develop/template/template_chat.zh.mdx | 14 +- .../develop/template/template_workflow.ja.mdx | 124 ++++++++-------- .../develop/template/template_workflow.zh.mdx | 12 +- .../workflow/nodes/code/code-parser.spec.ts | 6 +- .../workflow/nodes/code/code-parser.ts | 2 +- web/i18n/README.md | 4 +- web/i18n/en-US/education.ts | 2 +- web/i18n/hi-IN/dataset-settings.ts | 2 +- web/i18n/ja-JP/app-annotation.ts | 4 +- web/i18n/ja-JP/app-api.ts | 42 +++--- web/i18n/ja-JP/app-debug.ts | 74 +++++----- web/i18n/ja-JP/app-log.ts | 16 +-- web/i18n/ja-JP/app-overview.ts | 88 ++++++------ web/i18n/ja-JP/app.ts | 66 ++++----- web/i18n/ja-JP/billing.ts | 40 +++--- web/i18n/ja-JP/common.ts | 136 +++++++++--------- web/i18n/ja-JP/custom.ts | 10 +- web/i18n/ja-JP/dataset-creation.ts | 90 ++++++------ web/i18n/ja-JP/dataset-documents.ts | 38 ++--- web/i18n/ja-JP/dataset-hit-testing.ts | 2 +- web/i18n/ja-JP/dataset-settings.ts | 12 +- web/i18n/ja-JP/dataset.ts | 74 +++++----- web/i18n/ja-JP/education.ts | 14 +- web/i18n/ja-JP/login.ts | 44 +++--- web/i18n/ja-JP/plugin.ts | 32 ++--- web/i18n/ja-JP/run-log.ts | 2 +- web/i18n/ja-JP/share-app.ts | 20 +-- web/i18n/ja-JP/time.ts | 24 ++-- web/i18n/ja-JP/tools.ts | 34 ++--- web/i18n/ja-JP/workflow.ts | 128 ++++++++--------- web/i18n/ko-KR/app-api.ts | 26 ++-- web/i18n/ko-KR/app-debug.ts | 32 ++--- web/i18n/ko-KR/app-log.ts | 12 +- web/i18n/ko-KR/app-overview.ts | 40 +++--- web/i18n/ko-KR/app.ts | 22 +-- web/i18n/ko-KR/billing.ts | 16 +-- web/i18n/ko-KR/common.ts | 40 +++--- web/i18n/ko-KR/custom.ts | 4 +- web/i18n/ko-KR/dataset-creation.ts | 64 ++++----- web/i18n/ko-KR/dataset-documents.ts | 48 +++---- web/i18n/ko-KR/dataset-hit-testing.ts | 4 +- web/i18n/ko-KR/dataset-settings.ts | 4 +- web/i18n/ko-KR/dataset.ts | 36 ++--- web/i18n/ko-KR/education.ts | 8 +- web/i18n/ko-KR/explore.ts | 2 +- web/i18n/ko-KR/login.ts | 34 ++--- web/i18n/ko-KR/plugin.ts | 24 ++-- web/i18n/ko-KR/share-app.ts | 4 +- web/i18n/ko-KR/time.ts | 24 ++-- web/i18n/ko-KR/tools.ts | 8 +- web/i18n/ko-KR/workflow.ts | 64 ++++----- web/i18n/language.ts | 2 +- web/i18n/vi-VN/workflow.ts | 2 +- web/i18n/zh-Hans/app-api.ts | 4 +- web/i18n/zh-Hans/app-debug.ts | 12 +- web/i18n/zh-Hans/app-overview.ts | 8 +- web/i18n/zh-Hans/app.ts | 6 +- web/i18n/zh-Hans/common.ts | 14 +- web/i18n/zh-Hans/dataset-creation.ts | 18 +-- web/i18n/zh-Hans/dataset.ts | 8 +- web/i18n/zh-Hans/login.ts | 4 +- web/i18n/zh-Hans/plugin.ts | 4 +- web/i18n/zh-Hans/share-app.ts | 4 +- web/i18n/zh-Hans/tools.ts | 10 +- web/i18n/zh-Hans/workflow.ts | 16 +-- web/i18n/zh-Hant/app-api.ts | 4 +- web/i18n/zh-Hant/app-debug.ts | 12 +- web/i18n/zh-Hant/app-overview.ts | 12 +- web/i18n/zh-Hant/app.ts | 20 +-- web/i18n/zh-Hant/billing.ts | 12 +- web/i18n/zh-Hant/common.ts | 22 +-- web/i18n/zh-Hant/dataset-creation.ts | 14 +- web/i18n/zh-Hant/dataset-documents.ts | 2 +- web/i18n/zh-Hant/dataset-settings.ts | 2 +- web/i18n/zh-Hant/dataset.ts | 10 +- web/i18n/zh-Hant/education.ts | 6 +- web/i18n/zh-Hant/login.ts | 8 +- web/i18n/zh-Hant/plugin.ts | 6 +- web/i18n/zh-Hant/share-app.ts | 4 +- web/i18n/zh-Hant/tools.ts | 8 +- web/i18n/zh-Hant/workflow.ts | 38 ++--- 91 files changed, 1109 insertions(+), 1119 deletions(-) diff --git a/api/core/rag/datasource/keyword/jieba/stopwords.py b/api/core/rag/datasource/keyword/jieba/stopwords.py index 9abe78d6ef..54b65d9a2d 100644 --- a/api/core/rag/datasource/keyword/jieba/stopwords.py +++ b/api/core/rag/datasource/keyword/jieba/stopwords.py @@ -720,7 +720,7 @@ STOPWORDS = { "〉", "〈", "…", - " ", + " ", "0", "1", "2", @@ -731,16 +731,6 @@ STOPWORDS = { "7", "8", "9", - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", "二", "三", "四", diff --git a/api/core/rag/datasource/vdb/oracle/oraclevector.py b/api/core/rag/datasource/vdb/oracle/oraclevector.py index 0a3738ac93..6b9dd9c561 100644 --- a/api/core/rag/datasource/vdb/oracle/oraclevector.py +++ b/api/core/rag/datasource/vdb/oracle/oraclevector.py @@ -261,7 +261,7 @@ class OracleVector(BaseVector): words = pseg.cut(query) current_entity = "" for word, pos in words: - if pos in {"nr", "Ng", "eng", "nz", "n", "ORG", "v"}: # nr: 人名, ns: 地名, nt: 机构名 + if pos in {"nr", "Ng", "eng", "nz", "n", "ORG", "v"}: # nr: 人名,ns: 地名,nt: 机构名 current_entity += word else: if current_entity: diff --git a/web/app/(commonLayout)/datasets/template/template.ja.mdx b/web/app/(commonLayout)/datasets/template/template.ja.mdx index b9fab19948..a796b65bae 100644 --- a/web/app/(commonLayout)/datasets/template/template.ja.mdx +++ b/web/app/(commonLayout)/datasets/template/template.ja.mdx @@ -192,15 +192,15 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi - original_document_id が渡されない場合、新しい操作が実行され、process_rule が必要です。 - indexing_technique インデックスモード - - high_quality 高品質: 埋め込みモデルを使用してベクトルデータベースインデックスを構築 - - economy 経済: キーワードテーブルインデックスの反転インデックスを構築 + - high_quality 高品質:埋め込みモデルを使用してベクトルデータベースインデックスを構築 + - economy 経済:キーワードテーブルインデックスの反転インデックスを構築 - doc_form インデックス化された内容の形式 - text_model テキストドキュメントは直接埋め込まれます; `economy` モードではこの形式がデフォルト - hierarchical_model 親子モード - - qa_model Q&A モード: 分割されたドキュメントの質問と回答ペアを生成し、質問を埋め込みます + - qa_model Q&A モード:分割されたドキュメントの質問と回答ペアを生成し、質問を埋め込みます - - doc_language Q&A モードでは、ドキュメントの言語を指定します。例: English, Chinese + - doc_language Q&A モードでは、ドキュメントの言語を指定します。例:English, Chinese - process_rule 処理ルール - mode (string) クリーニング、セグメンテーションモード、自動 / カスタム @@ -214,7 +214,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi - segmentation (object) セグメンテーションルール - separator カスタムセグメント識別子。現在は 1 つの区切り文字のみ設定可能。デフォルトは \n - max_tokens 最大長 (トークン) デフォルトは 1000 - - parent_mode 親チャンクの検索モード: full-doc 全文検索 / paragraph 段落検索 + - parent_mode 親チャンクの検索モード:full-doc 全文検索 / paragraph 段落検索 - subchunk_segmentation (object) 子チャンクルール - separator セグメンテーション識別子。現在は 1 つの区切り文字のみ許可。デフォルトは *** - max_tokens 最大長 (トークン) は親チャンクの長さより短いことを検証する必要があります @@ -324,7 +324,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi - partial_members 一部のメンバー - プロバイダー (オプション、デフォルト: vendor) + プロバイダー (オプション、デフォルト:vendor) - vendor ベンダー - external 外部ナレッジ @@ -415,16 +415,16 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi 検索キーワード、オプション - タグIDリスト、オプション + タグ ID リスト、オプション - ページ番号、オプション、デフォルト1 + ページ番号、オプション、デフォルト 1 - 返されるアイテム数、オプション、デフォルト20、範囲1-100 + 返されるアイテム数、オプション、デフォルト 20、範囲 1-100 - すべてのデータセットを含めるかどうか(所有者のみ有効)、オプション、デフォルトはfalse + すべてのデータセットを含めるかどうか(所有者のみ有効)、オプション、デフォルトは false @@ -2013,7 +2013,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (text) 新しいタグ名、必須、最大長50文字 + (text) 新しいタグ名、必須、最大長 50 文字 @@ -2099,10 +2099,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (text) 変更後のタグ名、必須、最大長50文字 + (text) 変更後のタグ名、必須、最大長 50 文字 - (text) タグID、必須 + (text) タグ ID、必須 @@ -2147,7 +2147,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (text) タグID、必須 + (text) タグ ID、必須 @@ -2188,10 +2188,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (list) タグIDリスト、必須 + (list) タグ ID リスト、必須 - (text) ナレッジベースID、必須 + (text) ナレッジベース ID、必須 @@ -2230,10 +2230,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (text) タグID、必須 + (text) タグ ID、必須 - (text) ナレッジベースID、必須 + (text) ナレッジベース ID、必須 @@ -2273,7 +2273,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Path - (text) ナレッジベースID + (text) ナレッジベース ID diff --git a/web/app/(commonLayout)/datasets/template/template.zh.mdx b/web/app/(commonLayout)/datasets/template/template.zh.mdx index b10f22002a..08ef5d562a 100644 --- a/web/app/(commonLayout)/datasets/template/template.zh.mdx +++ b/web/app/(commonLayout)/datasets/template/template.zh.mdx @@ -207,7 +207,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi - doc_language 在 Q&A 模式下,指定文档的语言,例如:EnglishChinese - process_rule 处理规则 - - mode (string) 清洗、分段模式 ,automatic 自动 / custom 自定义 / hierarchical 父子 + - mode (string) 清洗、分段模式,automatic 自动 / custom 自定义 / hierarchical 父子 - rules (object) 自定义规则(自动模式下,该字段为空) - pre_processing_rules (array[object]) 预处理规则 - id (string) 预处理规则的唯一标识符 @@ -234,12 +234,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi - hybrid_search 混合检索 - semantic_search 语义检索 - full_text_search 全文检索 - - reranking_enable (bool) 是否开启rerank + - reranking_enable (bool) 是否开启 rerank - reranking_model (object) Rerank 模型配置 - reranking_provider_name (string) Rerank 模型的提供商 - reranking_model_name (string) Rerank 模型的名称 - top_k (int) 召回条数 - - score_threshold_enabled (bool)是否开启召回分数限制 + - score_threshold_enabled (bool) 是否开启召回分数限制 - score_threshold (float) 召回分数限制 @@ -350,12 +350,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi - hybrid_search 混合检索 - semantic_search 语义检索 - full_text_search 全文检索 - - reranking_enable (bool) 是否开启rerank + - reranking_enable (bool) 是否开启 rerank - reranking_model (object) Rerank 模型配置 - reranking_provider_name (string) Rerank 模型的提供商 - reranking_model_name (string) Rerank 模型的名称 - top_k (int) 召回条数 - - score_threshold_enabled (bool)是否开启召回分数限制 + - score_threshold_enabled (bool) 是否开启召回分数限制 - score_threshold (float) 召回分数限制 @@ -1322,7 +1322,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi 文档 ID - 文档分段ID + 文档分段 ID @@ -1435,7 +1435,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi 文档 ID - 文档分段ID + 文档分段 ID @@ -2404,7 +2404,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (text) 新标签名称,必填,最大长度为50 + (text) 新标签名称,必填,最大长度为 50 @@ -2490,10 +2490,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (text) 修改后的标签名称,必填,最大长度为50 + (text) 修改后的标签名称,必填,最大长度为 50 - (text) 标签ID,必填 + (text) 标签 ID,必填 @@ -2538,7 +2538,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (text) 标签ID,必填 + (text) 标签 ID,必填 @@ -2579,10 +2579,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (list) 标签ID列表,必填 + (list) 标签 ID 列表,必填 - (text) 知识库ID,必填 + (text) 知识库 ID,必填 @@ -2621,10 +2621,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Request Body - (text) 标签ID,必填 + (text) 标签 ID,必填 - (text) 知识库ID,必填 + (text) 知识库 ID,必填 @@ -2664,7 +2664,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi ### Path - (text) 知识库ID + (text) 知识库 ID diff --git a/web/app/components/base/chat/chat/answer/__mocks__/markdownContentSVG.ts b/web/app/components/base/chat/chat/answer/__mocks__/markdownContentSVG.ts index bcc3ae628d..51995a4af5 100644 --- a/web/app/components/base/chat/chat/answer/__mocks__/markdownContentSVG.ts +++ b/web/app/components/base/chat/chat/answer/__mocks__/markdownContentSVG.ts @@ -3,7 +3,7 @@ export const markdownContentSVG = ` - 创意Logo设计 + 创意 Logo 设计 diff --git a/web/app/components/develop/template/template.ja.mdx b/web/app/components/develop/template/template.ja.mdx index 5380d4da91..fc6291f522 100755 --- a/web/app/components/develop/template/template.ja.mdx +++ b/web/app/components/develop/template/template.ja.mdx @@ -3,10 +3,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from # Completion アプリ API -テキスト生成アプリケーションはセッションレスをサポートし、翻訳、記事作成、要約AI等に最適です。 +テキスト生成アプリケーションはセッションレスをサポートし、翻訳、記事作成、要約 AI 等に最適です。
- ### ベースURL + ### ベース URL ```javascript ``` @@ -14,10 +14,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ### 認証 - サービスAPIは`API-Key`認証を使用します。 - **APIキーの漏洩による重大な結果を避けるため、APIキーはサーバーサイドに保存し、クライアントサイドでは共有や保存しないことを強く推奨します。** + サービス API は `API-Key` 認証を使用します。 + **API キーの漏洩による重大な結果を避けるため、API キーはサーバーサイドに保存し、クライアントサイドでは共有や保存しないことを強く推奨します。** - すべてのAPIリクエストで、以下のように`Authorization` HTTPヘッダーにAPIキーを含めてください: + すべての API リクエストで、以下のように `Authorization` HTTP ヘッダーに API キーを含めてください: ```javascript @@ -212,7 +212,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
メッセージ送信時に使用するファイル(現在は画像のみ対応)をアップロードし、画像とテキストのマルチモーダルな理解を可能にします。 - png、jpg、jpeg、webp、gif形式に対応しています。 + png、jpg、jpeg、webp、gif 形式に対応しています。 アップロードされたファイルは、現在のエンドユーザーのみが使用できます。 ### リクエストボディ @@ -223,25 +223,25 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from 開発者のルールで定義されたユーザー識別子。アプリケーション内で一意である必要があります。 ### レスポンス - アップロードが成功すると、サーバーはファイルのIDと関連情報を返します。 + アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。 - `id` (uuid) ID - `name` (string) ファイル名 - `size` (int) ファイルサイズ(バイト) - `extension` (string) ファイル拡張子 - - `mime_type` (string) ファイルのMIMEタイプ + - `mime_type` (string) ファイルの MIME タイプ - `created_by` (uuid) エンドユーザーID - `created_at` (timestamp) 作成タイムスタンプ、例:1705395332 ### エラー - 400, `no_file_uploaded`, ファイルを提供する必要があります - - 400, `too_many_files`, 現在は1つのファイルのみ受け付けています + - 400, `too_many_files`, 現在は 1 つのファイルのみ受け付けています - 400, `unsupported_preview`, ファイルがプレビューに対応していません - 400, `unsupported_estimate`, ファイルが推定に対応していません - 413, `file_too_large`, ファイルが大きすぎます - 415, `unsupported_file_type`, サポートされていない拡張子です。現在はドキュメントファイルのみ受け付けています - - 503, `s3_connection_failed`, S3サービスに接続できません - - 503, `s3_permission_denied`, S3へのファイルアップロード権限がありません - - 503, `s3_file_too_large`, ファイルがS3のサイズ制限を超えています + - 503, `s3_connection_failed`, S3 サービスに接続できません + - 503, `s3_permission_denied`, S3 へのファイルアップロード権限がありません + - 503, `s3_file_too_large`, ファイルが S3 のサイズ制限を超えています - 500, 内部サーバーエラー @@ -286,7 +286,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ストリーミングモードでのみサポートされています。 ### パス - - `task_id` (string) タスクID、ストリーミングチャンクの返信から取得可能 + - `task_id` (string) タスク ID、ストリーミングチャンクの返信から取得可能 リクエストボディ - `user` (string) 必須 ユーザー識別子。エンドユーザーの身元を定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致する必要があります。 @@ -655,22 +655,22 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from /> - アプリのWebApp設定を取得するために使用します。 + アプリの WebApp 設定を取得するために使用します。 ### レスポンス - - `title` (string) WebApp名 - - `chat_color_theme` (string) チャットの色テーマ、16進数形式 + - `title` (string) WebApp 名 + - `chat_color_theme` (string) チャットの色テーマ、16 進数形式 - `chat_color_theme_inverted` (bool) チャットの色テーマを反転するかどうか - `icon_type` (string) アイコンタイプ、`emoji`-絵文字、`image`-画像 - - `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像URL - - `icon_background` (string) 16進数形式の背景色 - - `icon_url` (string) アイコンのURL + - `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像 URL + - `icon_background` (string) 16 進数形式の背景色 + - `icon_url` (string) アイコンの URL - `description` (string) 説明 - `copyright` (string) 著作権情報 - `privacy_policy` (string) プライバシーポリシーのリンク - `custom_disclaimer` (string) カスタム免責事項 - `default_language` (string) デフォルト言語 - `show_workflow_steps` (bool) ワークフローの詳細を表示するかどうか - - `use_icon_as_answer_icon` (bool) WebAppのアイコンをチャット内の🤖に置き換えるかどうか + - `use_icon_as_answer_icon` (bool) WebApp のアイコンをチャット内の🤖に置き換えるかどうか diff --git a/web/app/components/develop/template/template.zh.mdx b/web/app/components/develop/template/template.zh.mdx index 69d955b11f..9e65a4bd9b 100755 --- a/web/app/components/develop/template/template.zh.mdx +++ b/web/app/components/develop/template/template.zh.mdx @@ -60,7 +60,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' 上传的文件。 - `type` (string) 支持类型:图片 `image`(目前仅支持图片格式) 。 - - `transfer_method` (string) 传递方式: + - `transfer_method` (string) 传递方式: - `remote_url`: 图片地址。 - `local_file`: 上传文件。 - `url` 图片地址。(仅当传递方式为 `remote_url` 时)。 @@ -622,10 +622,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' 用于获取应用的 WebApp 设置 ### Response - `title` (string) WebApp 名称 - - `chat_color_theme` (string) 聊天颜色主题, hex 格式 + - `chat_color_theme` (string) 聊天颜色主题,hex 格式 - `chat_color_theme_inverted` (bool) 聊天颜色主题是否反转 - - `icon_type` (string) 图标类型, `emoji`-表情, `image`-图片 - - `icon` (string) 图标, 如果是 `emoji` 类型, 则是 emoji 表情符号, 如果是 `image` 类型, 则是图片 URL + - `icon_type` (string) 图标类型,`emoji`-表情,`image`-图片 + - `icon` (string) 图标,如果是 `emoji` 类型,则是 emoji 表情符号,如果是 `image` 类型,则是图片 URL - `icon_background` (string) hex 格式的背景色 - `icon_url` (string) 图标 URL - `description` (string) 描述 @@ -879,10 +879,10 @@ ___ 动作,只能是 'enable' 或 'disable' - 指定的嵌入模型提供商, 必须先在系统内设定好接入的模型,对应的是provider字段 + 指定的嵌入模型提供商,必须先在系统内设定好接入的模型,对应的是 provider 字段 - 指定的嵌入模型,对应的是model字段 + 指定的嵌入模型,对应的是 model 字段 相似度阈值,当相似度大于该阈值时,系统会自动回复,否则不回复 @@ -890,8 +890,8 @@ ___ - 嵌入模型的提供商和模型名称可以通过以下接口获取:v1/workspaces/current/models/model-types/text-embedding, 具体见:通过 API 维护知识库。 使用的Authorization是Dataset的API Token。 - 该接口是异步执行,所以会返回一个job_id,通过查询job状态接口可以获取到最终的执行结果。 + 嵌入模型的提供商和模型名称可以通过以下接口获取:v1/workspaces/current/models/model-types/text-embedding,具体见:通过 API 维护知识库。使用的 Authorization 是 Dataset 的 API Token。 + 该接口是异步执行,所以会返回一个 job_id,通过查询 job 状态接口可以获取到最终的执行结果。 - ### ベースURL + ### ベース URL ```javascript ``` @@ -14,10 +14,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ### 認証 - サービスAPIは`API-Key`認証を使用します。 - **APIキーはサーバー側に保存し、クライアント側で共有または保存しないことを強くお勧めします。APIキーの漏洩は深刻な結果を招く可能性があります。** + サービス API は `API-Key` 認証を使用します。 + **API キーはサーバー側に保存し、クライアント側で共有または保存しないことを強くお勧めします。API キーの漏洩は深刻な結果を招く可能性があります。** - すべてのAPIリクエストには、以下のように`Authorization`HTTPヘッダーにAPIキーを含めてください: + すべての API リクエストには、以下のように `Authorization`HTTP ヘッダーに API キーを含めてください: ```javascript @@ -327,25 +327,25 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ユーザー識別子、開発者のルールによって定義され、アプリケーション内で一意でなければなりません。 ### 応答 - アップロードが成功すると、サーバーはファイルのIDと関連情報を返します。 + アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。 - `id` (uuid) ID - `name` (string) ファイル名 - `size` (int) ファイルサイズ(バイト) - `extension` (string) ファイル拡張子 - - `mime_type` (string) ファイルのMIMEタイプ + - `mime_type` (string) ファイルの MIME タイプ - `created_by` (uuid) エンドユーザーID - `created_at` (timestamp) 作成タイムスタンプ、例:1705395332 ### エラー - 400, `no_file_uploaded`, ファイルが提供されなければなりません - - 400, `too_many_files`, 現在は1つのファイルのみ受け付けます + - 400, `too_many_files`, 現在は 1 つのファイルのみ受け付けます - 400, `unsupported_preview`, ファイルはプレビューをサポートしていません - 400, `unsupported_estimate`, ファイルは推定をサポートしていません - 413, `file_too_large`, ファイルが大きすぎます - 415, `unsupported_file_type`, サポートされていない拡張子、現在はドキュメントファイルのみ受け付けます - - 503, `s3_connection_failed`, S3サービスに接続できません - - 503, `s3_permission_denied`, S3にファイルをアップロードする権限がありません - - 503, `s3_file_too_large`, ファイルがS3のサイズ制限を超えています + - 503, `s3_connection_failed`, S3 サービスに接続できません + - 503, `s3_permission_denied`, S3 にファイルをアップロードする権限がありません + - 503, `s3_file_too_large`, ファイルが S3 のサイズ制限を超えています - 500, 内部サーバーエラー @@ -391,7 +391,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ストリーミングモードでのみサポートされています。 ### パス - - `task_id` (string) タスクID、ストリーミングチャンクの返り値から取得できます + - `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得できます ### リクエストボディ - `user` (string) 必須 ユーザー識別子、エンドユーザーの身元を定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。 @@ -712,7 +712,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from /> - 現在のユーザーの会話リストを取得し、デフォルトで最新の20件を返します。 + 現在のユーザーの会話リストを取得し、デフォルトで最新の 20 件を返します。 ### クエリ @@ -943,7 +943,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `limit` (int) ページごとのアイテム数 - `has_more` (bool) さらにアイテムがあるかどうか - `data` (array[object]) 変数のリスト - - `id` (string) 変数ID + - `id` (string) 変数 ID - `name` (string) 変数名 - `value_type` (string) 変数タイプ(文字列、数値、真偽値など) - `value` (string) 変数値 @@ -1014,7 +1014,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from /> - このエンドポイントはmultipart/form-dataリクエストを必要とします。 + このエンドポイントは multipart/form-data リクエストを必要とします。 ### リクエストボディ @@ -1288,9 +1288,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `tool_name` (string) - `icon` (object|string) - (object) アイコンオブジェクト - - `background` (string) 背景色(16進数形式) + - `background` (string) 背景色(16 進数形式) - `content`(string) 絵文字 - - (string) アイコンのURL + - (string) アイコンの URL @@ -1327,22 +1327,22 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from /> - アプリのWebApp設定を取得するために使用します。 + アプリの WebApp 設定を取得するために使用します。 ### 応答 - - `title` (string) WebApp名 - - `chat_color_theme` (string) チャットの色テーマ、16進数形式 + - `title` (string) WebApp 名 + - `chat_color_theme` (string) チャットの色テーマ、16 進数形式 - `chat_color_theme_inverted` (bool) チャットの色テーマを反転するかどうか - `icon_type` (string) アイコンタイプ、`emoji`-絵文字、`image`-画像 - - `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像URL - - `icon_background` (string) 16進数形式の背景色 - - `icon_url` (string) アイコンのURL + - `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像 URL + - `icon_background` (string) 16 進数形式の背景色 + - `icon_url` (string) アイコンの URL - `description` (string) 説明 - `copyright` (string) 著作権情報 - `privacy_policy` (string) プライバシーポリシーのリンク - `custom_disclaimer` (string) カスタム免責事項 - `default_language` (string) デフォルト言語 - `show_workflow_steps` (bool) ワークフローの詳細を表示するかどうか - - `use_icon_as_answer_icon` (bool) WebAppのアイコンをチャット内の🤖に置き換えるかどうか + - `use_icon_as_answer_icon` (bool) WebApp のアイコンをチャット内の🤖に置き換えるかどうか diff --git a/web/app/components/develop/template/template_advanced_chat.zh.mdx b/web/app/components/develop/template/template_advanced_chat.zh.mdx index 828b8d1f68..3e268d6e65 100755 --- a/web/app/components/develop/template/template_advanced_chat.zh.mdx +++ b/web/app/components/develop/template/template_advanced_chat.zh.mdx @@ -981,7 +981,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' - `limit` (int) 每页项目数 - `has_more` (bool) 是否有更多项目 - `data` (array[object]) 变量列表 - - `id` (string) 变量ID + - `id` (string) 变量 ID - `name` (string) 变量名称 - `value_type` (string) 变量类型(字符串、数字、布尔等) - `value` (string) 变量值 @@ -1300,15 +1300,15 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' /> - 用于获取工具icon + 用于获取工具 icon ### Response - `tool_icons`(object[string]) 工具图标 - `工具名称` (string) - `icon` (object|string) - (object) 图标 - - `background` (string) hex格式的背景色 + - `background` (string) hex 格式的背景色 - `content`(string) emoji - - (string) 图标URL + - (string) 图标 URL @@ -1347,10 +1347,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' 用于获取应用的 WebApp 设置 ### Response - `title` (string) WebApp 名称 - - `chat_color_theme` (string) 聊天颜色主题, hex 格式 + - `chat_color_theme` (string) 聊天颜色主题,hex 格式 - `chat_color_theme_inverted` (bool) 聊天颜色主题是否反转 - - `icon_type` (string) 图标类型, `emoji`-表情, `image`-图片 - - `icon` (string) 图标, 如果是 `emoji` 类型, 则是 emoji 表情符号, 如果是 `image` 类型, 则是图片 URL + - `icon_type` (string) 图标类型,`emoji`-表情,`image`-图片 + - `icon` (string) 图标,如果是 `emoji` 类型,则是 emoji 表情符号,如果是 `image` 类型,则是图片 URL - `icon_background` (string) hex 格式的背景色 - `icon_url` (string) 图标 URL - `description` (string) 描述 @@ -1604,10 +1604,10 @@ ___ 动作,只能是 'enable' 或 'disable' - 指定的嵌入模型提供商, 必须先在系统内设定好接入的模型,对应的是provider字段 + 指定的嵌入模型提供商,必须先在系统内设定好接入的模型,对应的是 provider 字段 - 指定的嵌入模型,对应的是model字段 + 指定的嵌入模型,对应的是 model 字段 相似度阈值,当相似度大于该阈值时,系统会自动回复,否则不回复 @@ -1615,7 +1615,7 @@ ___ - 嵌入模型的提供商和模型名称可以通过以下接口获取:v1/workspaces/current/models/model-types/text-embedding, 具体见:通过 API 维护知识库。 使用的Authorization是Dataset的API Token。 + 嵌入模型的提供商和模型名称可以通过以下接口获取:v1/workspaces/current/models/model-types/text-embedding,具体见:通过 API 维护知识库。使用的 Authorization 是 Dataset 的 API Token。 - ### ベースURL + ### ベース URL ```javascript ``` @@ -14,10 +14,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ### 認証 - サービスAPIは`API-Key`認証を使用します。 - **APIキーの漏洩を防ぐため、APIキーはクライアント側で共有または保存せず、サーバー側で保存することを強くお勧めします。** + サービス API は `API-Key` 認証を使用します。 + **API キーの漏洩を防ぐため、API キーはクライアント側で共有または保存せず、サーバー側で保存することを強くお勧めします。** - すべてのAPIリクエストにおいて、以下のように`Authorization`HTTPヘッダーにAPIキーを含めてください: + すべての API リクエストにおいて、以下のように `Authorization`HTTP ヘッダーに API キーを含めてください: ```javascript @@ -279,7 +279,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from メッセージ送信時に使用するためのファイルをアップロードします(現在は画像のみサポート)。画像とテキストのマルチモーダル理解を可能にします。 - png、jpg、jpeg、webp、gif形式をサポートしています。 + png、jpg、jpeg、webp、gif 形式をサポートしています。 アップロードされたファイルは現在のエンドユーザーのみが使用できます。 ### リクエストボディ @@ -290,25 +290,25 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。 ### 応答 - アップロードが成功すると、サーバーはファイルのIDと関連情報を返します。 + アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。 - `id` (uuid) ID - `name` (string) ファイル名 - `size` (int) ファイルサイズ(バイト) - `extension` (string) ファイル拡張子 - - `mime_type` (string) ファイルのMIMEタイプ + - `mime_type` (string) ファイルの MIME タイプ - `created_by` (uuid) エンドユーザーID - `created_at` (timestamp) 作成タイムスタンプ、例:1705395332 ### エラー - 400, `no_file_uploaded`, ファイルが提供されなければなりません - - 400, `too_many_files`, 現在は1つのファイルのみ受け付けます + - 400, `too_many_files`, 現在は 1 つのファイルのみ受け付けます - 400, `unsupported_preview`, ファイルはプレビューをサポートしていません - 400, `unsupported_estimate`, ファイルは推定をサポートしていません - 413, `file_too_large`, ファイルが大きすぎます - 415, `unsupported_file_type`, サポートされていない拡張子、現在はドキュメントファイルのみ受け付けます - - 503, `s3_connection_failed`, S3サービスに接続できません - - 503, `s3_permission_denied`, S3にファイルをアップロードする権限がありません - - 503, `s3_file_too_large`, ファイルがS3のサイズ制限を超えています + - 503, `s3_connection_failed`, S3 サービスに接続できません + - 503, `s3_permission_denied`, S3 にファイルをアップロードする権限がありません + - 503, `s3_file_too_large`, ファイルが S3 のサイズ制限を超えています - 500, 内部サーバーエラー @@ -354,7 +354,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ストリーミングモードでのみサポートされています。 ### パス - - `task_id` (string) タスクID、ストリーミングチャンクの返り値から取得できます + - `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得できます ### リクエストボディ - `user` (string) 必須 ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、メッセージ送信インターフェースで渡されたユーザーと一致している必要があります。 @@ -745,7 +745,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from /> - 現在のユーザーの会話リストを取得し、デフォルトで最新の20件を返します。 + 現在のユーザーの会話リストを取得し、デフォルトで最新の 20 件を返します。 ### クエリ @@ -975,7 +975,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `limit` (int) ページごとのアイテム数 - `has_more` (bool) さらにアイテムがあるかどうか - `data` (array[object]) 変数のリスト - - `id` (string) 変数ID + - `id` (string) 変数 ID - `name` (string) 変数名 - `value_type` (string) 変数タイプ(文字列、数値、真偽値など) - `value` (string) 変数値 @@ -1046,7 +1046,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from /> - このエンドポイントはmultipart/form-dataリクエストを必要とします。 + このエンドポイントは multipart/form-data リクエストを必要とします。 ### リクエストボディ @@ -1315,9 +1315,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `tool_name` (string) - `icon` (object|string) - (object) アイコンオブジェクト - - `background` (string) 背景色(16進数形式) + - `background` (string) 背景色(16 進数形式) - `content`(string) 絵文字 - - (string) アイコンのURL + - (string) アイコンの URL @@ -1354,22 +1354,22 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from /> - アプリのWebApp設定を取得するために使用します。 + アプリの WebApp 設定を取得するために使用します。 ### 応答 - - `title` (string) WebApp名 - - `chat_color_theme` (string) チャットの色テーマ、16進数形式 + - `title` (string) WebApp 名 + - `chat_color_theme` (string) チャットの色テーマ、16 進数形式 - `chat_color_theme_inverted` (bool) チャットの色テーマを反転するかどうか - `icon_type` (string) アイコンタイプ、`emoji`-絵文字、`image`-画像 - - `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像URL - - `icon_background` (string) 16進数形式の背景色 - - `icon_url` (string) アイコンのURL + - `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像 URL + - `icon_background` (string) 16 進数形式の背景色 + - `icon_url` (string) アイコンの URL - `description` (string) 説明 - `copyright` (string) 著作権情報 - `privacy_policy` (string) プライバシーポリシーのリンク - `custom_disclaimer` (string) カスタム免責事項 - `default_language` (string) デフォルト言語 - `show_workflow_steps` (bool) ワークフローの詳細を表示するかどうか - - `use_icon_as_answer_icon` (bool) WebAppのアイコンをチャット内の🤖に置き換えるかどうか + - `use_icon_as_answer_icon` (bool) WebApp のアイコンをチャット内の🤖に置き換えるかどうか diff --git a/web/app/components/develop/template/template_chat.zh.mdx b/web/app/components/develop/template/template_chat.zh.mdx index 233e68d42f..9c1a168bf5 100644 --- a/web/app/components/develop/template/template_chat.zh.mdx +++ b/web/app/components/develop/template/template_chat.zh.mdx @@ -991,7 +991,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' - `limit` (int) 每页项目数 - `has_more` (bool) 是否有更多项目 - `data` (array[object]) 变量列表 - - `id` (string) 变量ID + - `id` (string) 变量 ID - `name` (string) 变量名称 - `value_type` (string) 变量类型(字符串、数字、布尔等) - `value` (string) 变量值 @@ -1305,15 +1305,15 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' /> - 用于获取工具icon + 用于获取工具 icon ### Response - `tool_icons`(object[string]) 工具图标 - `工具名称` (string) - `icon` (object|string) - (object) 图标 - - `background` (string) hex格式的背景色 + - `background` (string) hex 格式的背景色 - `content`(string) emoji - - (string) 图标URL + - (string) 图标 URL @@ -1353,10 +1353,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' 用于获取应用的 WebApp 设置 ### Response - `title` (string) WebApp 名称 - - `chat_color_theme` (string) 聊天颜色主题, hex 格式 + - `chat_color_theme` (string) 聊天颜色主题,hex 格式 - `chat_color_theme_inverted` (bool) 聊天颜色主题是否反转 - - `icon_type` (string) 图标类型, `emoji`-表情, `image`-图片 - - `icon` (string) 图标, 如果是 `emoji` 类型, 则是 emoji 表情符号, 如果是 `image` 类型, 则是图片 URL + - `icon_type` (string) 图标类型,`emoji`-表情,`image`-图片 + - `icon` (string) 图标,如果是 `emoji` 类型,则是 emoji 表情符号,如果是 `image` 类型,则是图片 URL - `icon_background` (string) hex 格式的背景色 - `icon_url` (string) 图标 URL - `description` (string) 描述 diff --git a/web/app/components/develop/template/template_workflow.ja.mdx b/web/app/components/develop/template/template_workflow.ja.mdx index 3ab286d28a..ab53d05e81 100644 --- a/web/app/components/develop/template/template_workflow.ja.mdx +++ b/web/app/components/develop/template/template_workflow.ja.mdx @@ -1,12 +1,12 @@ import { CodeGroup } from '../code.tsx' import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from '../md.tsx' -# ワークフローアプリAPI +# ワークフローアプリ API -ワークフローアプリケーションは、セッションをサポートせず、翻訳、記事作成、要約AIなどに最適です。 +ワークフローアプリケーションは、セッションをサポートせず、翻訳、記事作成、要約 AI などに最適です。
- ### ベースURL + ### ベース URL ```javascript ``` @@ -14,10 +14,10 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ### 認証 - サービスAPIは`API-Key`認証を使用します。 - **APIキーの漏洩を防ぐため、APIキーはクライアント側で共有または保存せず、サーバー側で保存することを強くお勧めします。** + サービス API は `API-Key` 認証を使用します。 + **API キーの漏洩を防ぐため、API キーはクライアント側で共有または保存せず、サーバー側で保存することを強くお勧めします。** - すべてのAPIリクエストにおいて、以下のように`Authorization`HTTPヘッダーにAPIキーを含めてください: + すべての API リクエストにおいて、以下のように `Authorization`HTTP ヘッダーに API キーを含めてください: ```javascript @@ -61,7 +61,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from 応答の返却モードを指定します。サポートされているモード: - `streaming` ストリーミングモード(推奨)、SSE([Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events))を通じてタイプライターのような出力を実装します。 - `blocking` ブロッキングモード、実行完了後に結果を返します。(プロセスが長い場合、リクエストが中断される可能性があります) - Cloudflareの制限により、100秒後に応答がない場合、リクエストは中断されます。 + Cloudflare の制限により、100 秒後に応答がない場合、リクエストは中断されます。 - `user` (string) 必須 ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用されます。 アプリケーション内で開発者によって一意に定義される必要があります。 @@ -69,28 +69,28 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ### 応答 - `response_mode`が`blocking`の場合、CompletionResponseオブジェクトを返します。 - `response_mode`が`streaming`の場合、ChunkCompletionResponseストリームを返します。 + `response_mode`が`blocking`の場合、CompletionResponse オブジェクトを返します。 + `response_mode`が`streaming`の場合、ChunkCompletionResponse ストリームを返します。 ### CompletionResponse アプリの結果を返します。`Content-Type`は`application/json`です。 - - `workflow_run_id` (string) ワークフロー実行の一意のID - - `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用 + - `workflow_run_id` (string) ワークフロー実行の一意の ID + - `task_id` (string) タスク ID、リクエスト追跡と以下の Stop Generate API に使用 - `data` (object) 結果の詳細 - - `id` (string) ワークフロー実行のID - - `workflow_id` (string) 関連するワークフローのID + - `id` (string) ワークフロー実行の ID + - `workflow_id` (string) 関連するワークフローの ID - `status` (string) 実行のステータス、`running` / `succeeded` / `failed` / `stopped` - `outputs` (json) オプションの出力内容 - `error` (string) オプションのエラー理由 - `elapsed_time` (float) オプションの使用時間(秒) - `total_tokens` (int) オプションの使用トークン数 - - `total_steps` (int) デフォルト0 + - `total_steps` (int) デフォルト 0 - `created_at` (timestamp) 開始時間 - `finished_at` (timestamp) 終了時間 ### ChunkCompletionResponse アプリによって出力されたストリームチャンクを返します。`Content-Type`は`text/event-stream`です。 - 各ストリーミングチャンクは`data:`で始まり、2つの改行文字`\n\n`で区切られます。以下のように表示されます: + 各ストリーミングチャンクは`data:`で始まり、2 つの改行文字`\n\n`で区切られます。以下のように表示されます: ```streaming {{ title: '応答' }} data: {"event": "text_chunk", "workflow_run_id": "b85e5fc5-751b-454d-b14e-dc5f240b0a31", "task_id": "bd029338-b068-4d34-a331-fc85478922c2", "data": {"text": "\u4e3a\u4e86", "from_variable_selector": ["1745912968134", "text"]}}\n\n @@ -98,45 +98,45 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ストリーミングチャンクの構造は`event`に応じて異なります: - `event: workflow_started` ワークフローが実行を開始 - - `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用 - - `workflow_run_id` (string) ワークフロー実行の一意のID + - `task_id` (string) タスク ID、リクエスト追跡と以下の Stop Generate API に使用 + - `workflow_run_id` (string) ワークフロー実行の一意の ID - `event` (string) `workflow_started`に固定 - `data` (object) 詳細 - - `id` (string) ワークフロー実行の一意のID - - `workflow_id` (string) 関連するワークフローのID - - `sequence_number` (int) 自己増加シリアル番号、アプリ内で自己増加し、1から始まります + - `id` (string) ワークフロー実行の一意の ID + - `workflow_id` (string) 関連するワークフローの ID + - `sequence_number` (int) 自己増加シリアル番号、アプリ内で自己増加し、1 から始まります - `created_at` (timestamp) 作成タイムスタンプ、例:1705395332 - `event: node_started` ノード実行開始 - - `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用 - - `workflow_run_id` (string) ワークフロー実行の一意のID + - `task_id` (string) タスク ID、リクエスト追跡と以下の Stop Generate API に使用 + - `workflow_run_id` (string) ワークフロー実行の一意の ID - `event` (string) `node_started`に固定 - `data` (object) 詳細 - - `id` (string) ワークフロー実行の一意のID - - `node_id` (string) ノードのID + - `id` (string) ワークフロー実行の一意の ID + - `node_id` (string) ノードの ID - `node_type` (string) ノードのタイプ - `title` (string) ノードの名前 - `index` (int) 実行シーケンス番号、トレースノードシーケンスを表示するために使用 - - `predecessor_node_id` (string) オプションのプレフィックスノードID、キャンバス表示実行パスに使用 + - `predecessor_node_id` (string) オプションのプレフィックスノード ID、キャンバス表示実行パスに使用 - `inputs` (object) ノードで使用されるすべての前のノード変数の内容 - `created_at` (timestamp) 開始のタイムスタンプ、例:1705395332 - `event: text_chunk` テキストフラグメント - - `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用 - - `workflow_run_id` (string) ワークフロー実行の一意のID + - `task_id` (string) タスク ID、リクエスト追跡と以下の Stop Generate API に使用 + - `workflow_run_id` (string) ワークフロー実行の一意の ID - `event` (string) `text_chunk`に固定 - `data` (object) 詳細 - `text` (string) テキスト内容 - `from_variable_selector` (array) テキスト生成元パス(開発者がどのノードのどの変数から生成されたかを理解するための情報) - `event: node_finished` ノード実行終了、同じイベントで異なる状態で成功または失敗 - - `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用 - - `workflow_run_id` (string) ワークフロー実行の一意のID + - `task_id` (string) タスク ID、リクエスト追跡と以下の Stop Generate API に使用 + - `workflow_run_id` (string) ワークフロー実行の一意の ID - `event` (string) `node_finished`に固定 - `data` (object) 詳細 - - `id` (string) ワークフロー実行の一意のID - - `node_id` (string) ノードのID + - `id` (string) ワークフロー実行の一意の ID + - `node_id` (string) ノードの ID - `node_type` (string) ノードのタイプ - `title` (string) ノードの名前 - `index` (int) 実行シーケンス番号、トレースノードシーケンスを表示するために使用 - - `predecessor_node_id` (string) オプションのプレフィックスノードID、キャンバス表示実行パスに使用 + - `predecessor_node_id` (string) オプションのプレフィックスノード ID、キャンバス表示実行パスに使用 - `inputs` (object) ノードで使用されるすべての前のノード変数の内容 - `process_data` (json) オプションのノードプロセスデータ - `outputs` (json) オプションの出力内容 @@ -149,31 +149,31 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `currency` (string) オプション 例:`USD` / `RMB` - `created_at` (timestamp) 開始のタイムスタンプ、例:1705395332 - `event: workflow_finished` ワークフロー実行終了、同じイベントで異なる状態で成功または失敗 - - `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用 - - `workflow_run_id` (string) ワークフロー実行の一意のID + - `task_id` (string) タスク ID、リクエスト追跡と以下の Stop Generate API に使用 + - `workflow_run_id` (string) ワークフロー実行の一意の ID - `event` (string) `workflow_finished`に固定 - `data` (object) 詳細 - - `id` (string) ワークフロー実行のID - - `workflow_id` (string) 関連するワークフローのID + - `id` (string) ワークフロー実行の ID + - `workflow_id` (string) 関連するワークフローの ID - `status` (string) 実行のステータス、`running` / `succeeded` / `failed` / `stopped` - `outputs` (json) オプションの出力内容 - `error` (string) オプションのエラー理由 - `elapsed_time` (float) オプションの使用時間(秒) - `total_tokens` (int) オプションの使用トークン数 - - `total_steps` (int) デフォルト0 + - `total_steps` (int) デフォルト 0 - `created_at` (timestamp) 開始時間 - `finished_at` (timestamp) 終了時間 - - `event: tts_message` TTSオーディオストリームイベント、つまり音声合成出力。内容はMp3形式のオーディオブロックで、base64文字列としてエンコードされています。再生時には、base64をデコードしてプレーヤーに入力するだけです。(このメッセージは自動再生が有効な場合にのみ利用可能) - - `task_id` (string) タスクID、リクエスト追跡と以下の停止応答インターフェースに使用 - - `message_id` (string) 一意のメッセージID - - `audio` (string) 音声合成後のオーディオ、base64テキストコンテンツとしてエンコードされており、再生時にはbase64をデコードしてプレーヤーに入力するだけです + - `event: tts_message` TTS オーディオストリームイベント、つまり音声合成出力。内容は Mp3 形式のオーディオブロックで、base64 文字列としてエンコードされています。再生時には、base64 をデコードしてプレーヤーに入力するだけです。(このメッセージは自動再生が有効な場合にのみ利用可能) + - `task_id` (string) タスク ID、リクエスト追跡と以下の停止応答インターフェースに使用 + - `message_id` (string) 一意のメッセージ ID + - `audio` (string) 音声合成後のオーディオ、base64 テキストコンテンツとしてエンコードされており、再生時には base64 をデコードしてプレーヤーに入力するだけです - `created_at` (int) 作成タイムスタンプ、例:1705395332 - - `event: tts_message_end` TTSオーディオストリーム終了イベント。このイベントを受信すると、オーディオストリームの終了を示します。 - - `task_id` (string) タスクID、リクエスト追跡と以下の停止応答インターフェースに使用 - - `message_id` (string) 一意のメッセージID + - `event: tts_message_end` TTS オーディオストリーム終了イベント。このイベントを受信すると、オーディオストリームの終了を示します。 + - `task_id` (string) タスク ID、リクエスト追跡と以下の停止応答インターフェースに使用 + - `message_id` (string) 一意のメッセージ ID - `audio` (string) 終了イベントにはオーディオがないため、これは空の文字列です - `created_at` (int) 作成タイムスタンプ、例:1705395332 - - `event: ping` 接続を維持するために10秒ごとに送信されるPingイベント。 + - `event: ping` 接続を維持するために 10 秒ごとに送信される Ping イベント。 ### エラー - 400, `invalid_param`, 異常なパラメータ入力 @@ -342,12 +342,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from />
- ワークフロー実行IDに基づいて、ワークフロータスクの現在の実行結果を取得します。 + ワークフロー実行 ID に基づいて、ワークフロータスクの現在の実行結果を取得します。 ### パス - `workflow_id` (string) ワークフローID、ストリーミングチャンクの返り値から取得可能 ### 応答 - - `id` (string) ワークフロー実行のID - - `workflow_id` (string) 関連するワークフローのID + - `id` (string) ワークフロー実行の ID + - `workflow_id` (string) 関連するワークフローの ID - `status` (string) 実行のステータス、`running` / `succeeded` / `failed` / `stopped` - `inputs` (json) 入力内容 - `outputs` (json) 出力内容 @@ -401,7 +401,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ストリーミングモードでのみサポートされています。 ### パス - - `task_id` (string) タスクID、ストリーミングチャンクの返り値から取得可能 + - `task_id` (string) タスク ID、ストリーミングチャンクの返り値から取得可能 ### リクエストボディ - `user` (string) 必須 ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用され、送信メッセージインターフェースで渡されたユーザーと一致している必要があります。 @@ -454,25 +454,25 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from ユーザー識別子、開発者のルールで定義され、アプリケーション内で一意でなければなりません。 ### 応答 - アップロードが成功すると、サーバーはファイルのIDと関連情報を返します。 + アップロードが成功すると、サーバーはファイルの ID と関連情報を返します。 - `id` (uuid) ID - `name` (string) ファイル名 - `size` (int) ファイルサイズ(バイト) - `extension` (string) ファイル拡張子 - - `mime_type` (string) ファイルのMIMEタイプ + - `mime_type` (string) ファイルの MIME タイプ - `created_by` (uuid) エンドユーザーID - `created_at` (timestamp) 作成タイムスタンプ、例:1705395332 ### エラー - 400, `no_file_uploaded`, ファイルが提供されていません - - 400, `too_many_files`, 現在は1つのファイルのみ受け付けています + - 400, `too_many_files`, 現在は 1 つのファイルのみ受け付けています - 400, `unsupported_preview`, ファイルはプレビューをサポートしていません - 400, `unsupported_estimate`, ファイルは推定をサポートしていません - 413, `file_too_large`, ファイルが大きすぎます - 415, `unsupported_file_type`, サポートされていない拡張子、現在はドキュメントファイルのみ受け付けています - - 503, `s3_connection_failed`, S3サービスに接続できません - - 503, `s3_permission_denied`, S3にファイルをアップロードする権限がありません - - 503, `s3_file_too_large`, ファイルがS3のサイズ制限を超えています + - 503, `s3_connection_failed`, S3 サービスに接続できません + - 503, `s3_permission_denied`, S3 にファイルをアップロードする権限がありません + - 503, `s3_file_too_large`, ファイルが S3 のサイズ制限を超えています - 500, 内部サーバーエラー @@ -550,7 +550,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `error` (string) オプションのエラー理由 - `elapsed_time` (float) 使用される総秒数 - `total_tokens` (int) 使用されるトークン数 - - `total_steps` (int) デフォルト0 + - `total_steps` (int) デフォルト 0 - `created_at` (timestamp) 開始時間 - `finished_at` (timestamp) 終了時間 - `created_from` (string) 作成元 @@ -560,7 +560,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - `id` (string) ID - `type` (string) タイプ - `is_anonymous` (bool) 匿名かどうか - - `session_id` (string) セッションID + - `session_id` (string) セッション ID - `created_at` (timestamp) 作成時間 @@ -750,13 +750,13 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from /> - アプリのWebApp設定を取得するために使用します。 + アプリの WebApp 設定を取得するために使用します。 ### 応答 - - `title` (string) WebApp名 + - `title` (string) WebApp 名 - `icon_type` (string) アイコンタイプ、`emoji`-絵文字、`image`-画像 - - `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像URL - - `icon_background` (string) 16進数形式の背景色 - - `icon_url` (string) アイコンのURL + - `icon` (string) アイコン。`emoji`タイプの場合は絵文字、`image`タイプの場合は画像 URL + - `icon_background` (string) 16 進数形式の背景色 + - `icon_url` (string) アイコンの URL - `description` (string) 説明 - `copyright` (string) 著作権情報 - `privacy_policy` (string) プライバシーポリシーのリンク diff --git a/web/app/components/develop/template/template_workflow.zh.mdx b/web/app/components/develop/template/template_workflow.zh.mdx index 17690ec3d0..fe59988eda 100644 --- a/web/app/components/develop/template/template_workflow.zh.mdx +++ b/web/app/components/develop/template/template_workflow.zh.mdx @@ -346,7 +346,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 - `total_tokens` (int) 任务执行总 tokens - `created_at` (timestamp) 任务开始时间 - `finished_at` (timestamp) 任务结束时间 - - `elapsed_time` (float) 耗时(s) + - `elapsed_time` (float) 耗时 (s) ### Request Example @@ -505,7 +505,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 /> - 倒序返回workflow日志 + 倒序返回 workflow 日志 ### Query @@ -534,10 +534,10 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 - `workflow_run` (object) Workflow 执行日志 - `id` (string) 标识 - `version` (string) 版本 - - `status` (string) 执行状态, `running` / `succeeded` / `failed` / `stopped` + - `status` (string) 执行状态,`running` / `succeeded` / `failed` / `stopped` - `error` (string) (可选) 错误 - `elapsed_time` (float) 耗时,单位秒 - - `total_tokens` (int) 消耗的token数量 + - `total_tokens` (int) 消耗的 token 数量 - `total_steps` (int) 执行步骤长度 - `created_at` (timestamp) 开始时间 - `finished_at` (timestamp) 结束时间 @@ -741,8 +741,8 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 用于获取应用的 WebApp 设置 ### Response - `title` (string) WebApp 名称 - - `icon_type` (string) 图标类型, `emoji`-表情, `image`-图片 - - `icon` (string) 图标, 如果是 `emoji` 类型, 则是 emoji 表情符号, 如果是 `image` 类型, 则是图片 URL + - `icon_type` (string) 图标类型,`emoji`-表情,`image`-图片 + - `icon` (string) 图标,如果是 `emoji` 类型,则是 emoji 表情符号,如果是 `image` 类型,则是图片 URL - `icon_background` (string) hex 格式的背景色 - `icon_url` (string) 图标 URL - `description` (string) 描述 diff --git a/web/app/components/workflow/nodes/code/code-parser.spec.ts b/web/app/components/workflow/nodes/code/code-parser.spec.ts index b5d28dd136..67f2c218e1 100644 --- a/web/app/components/workflow/nodes/code/code-parser.spec.ts +++ b/web/app/components/workflow/nodes/code/code-parser.spec.ts @@ -57,7 +57,7 @@ describe('extractFunctionParams', () => { }) }) - // JavaScriptのテストケース + // JavaScript のテストケース describe('JavaScript', () => { test('handles no parameters', () => { const result = extractFunctionParams(SAMPLE_CODES.javascript.noParams, CodeLanguage.javascript) @@ -180,7 +180,7 @@ function main(name, age, city) { } describe('extractReturnType', () => { - // Python3のテスト + // Python3 のテスト describe('Python3', () => { test('extracts single return value', () => { const result = extractReturnType(RETURN_TYPE_SAMPLES.python3.singleReturn, CodeLanguage.python3) @@ -247,7 +247,7 @@ describe('extractReturnType', () => { }) }) - // JavaScriptのテスト + // JavaScript のテスト describe('JavaScript', () => { test('extracts single return value', () => { const result = extractReturnType(RETURN_TYPE_SAMPLES.javascript.singleReturn, CodeLanguage.javascript) diff --git a/web/app/components/workflow/nodes/code/code-parser.ts b/web/app/components/workflow/nodes/code/code-parser.ts index 0973a01bd0..216e13eaca 100644 --- a/web/app/components/workflow/nodes/code/code-parser.ts +++ b/web/app/components/workflow/nodes/code/code-parser.ts @@ -31,7 +31,7 @@ export const extractReturnType = (code: string, language: CodeLanguage): OutputV if (returnIndex === -1) return {} - // returnから始まる部分文字列を取得 + // return から始まる部分文字列を取得 const codeAfterReturn = codeWithoutComments.slice(returnIndex) let bracketCount = 0 diff --git a/web/i18n/README.md b/web/i18n/README.md index 9384ffc519..b81ffbf4c3 100644 --- a/web/i18n/README.md +++ b/web/i18n/README.md @@ -115,13 +115,13 @@ export const languages = [ }, { value: 'ja-JP', - name: '日本語(日本)', + name: '日本語 (日本)', example: 'こんにちは、Dify!', supported: false, }, { value: 'ko-KR', - name: '한국어(대한민국)', + name: '한국어 (대한민국)', example: '안녕, Dify!', supported: true, }, diff --git a/web/i18n/en-US/education.ts b/web/i18n/en-US/education.ts index ea125a1332..dd7fedc10f 100644 --- a/web/i18n/en-US/education.ts +++ b/web/i18n/en-US/education.ts @@ -24,7 +24,7 @@ const translation = { desc: { front: 'Your information and use of Education Verified status are subject to our', and: 'and', - end: '. By submitting:', + end: '. By submitting:', termsOfService: 'Terms of Service', privacyPolicy: 'Privacy Policy', }, diff --git a/web/i18n/hi-IN/dataset-settings.ts b/web/i18n/hi-IN/dataset-settings.ts index c89097d89e..9a05847ac8 100644 --- a/web/i18n/hi-IN/dataset-settings.ts +++ b/web/i18n/hi-IN/dataset-settings.ts @@ -1,6 +1,6 @@ const translation = { title: 'ज्ञान सेटिंग्ज', - desc: 'यहां आप ज्ञान की संपत्ति और कार्य प्रक्रियाओं को modify कर सकते हैं。', + desc: 'यहां आप ज्ञान की संपत्ति और कार्य प्रक्रियाओं को modify कर सकते हैं.', form: { name: 'ज्ञान नाम', namePlaceholder: 'कृपया ज्ञान नाम दर्ज करें', diff --git a/web/i18n/ja-JP/app-annotation.ts b/web/i18n/ja-JP/app-annotation.ts index 297e01d184..38b891d9d8 100644 --- a/web/i18n/ja-JP/app-annotation.ts +++ b/web/i18n/ja-JP/app-annotation.ts @@ -42,9 +42,9 @@ const translation = { }, batchModal: { title: '一括インポート', - csvUploadTitle: 'CSVファイルをここにドラッグ&ドロップするか、', + csvUploadTitle: 'CSV ファイルをここにドラッグ&ドロップするか、', browse: '参照', - tip: 'CSVファイルは以下の構造に準拠する必要があります:', + tip: 'CSV ファイルは以下の構造に準拠する必要があります:', question: '質問', answer: '回答', contentTitle: 'チャンクの内容', diff --git a/web/i18n/ja-JP/app-api.ts b/web/i18n/ja-JP/app-api.ts index 4d30a71a10..e344ad04a9 100644 --- a/web/i18n/ja-JP/app-api.ts +++ b/web/i18n/ja-JP/app-api.ts @@ -1,6 +1,6 @@ const translation = { - apiServer: 'APIサーバー', - apiKey: 'APIキー', + apiServer: 'API サーバー', + apiKey: 'API キー', status: 'ステータス', disabled: '無効', ok: '稼働中', @@ -15,8 +15,8 @@ const translation = { }, never: 'なし', apiKeyModal: { - apiSecretKey: 'APIシークレットキー', - apiSecretKeyTips: 'APIの悪用を防ぐために、APIキーを保護してください。フロントエンドのコードで平文として使用しないでください。:)', + apiSecretKey: 'API シークレットキー', + apiSecretKeyTips: 'API の悪用を防ぐために、API キーを保護してください。フロントエンドのコードで平文として使用しないでください。:)', createNewSecretKey: '新しいシークレットキーを作成', secretKey: 'シークレットキー', created: '作成日時', @@ -29,44 +29,44 @@ const translation = { ok: 'OK', }, completionMode: { - title: '補完アプリAPI', - info: '記事、要約、翻訳などの高品質なテキスト生成には、ユーザーの入力を使用した補完メッセージAPIを使用します。テキスト生成は、Dify Prompt Engineeringで設定されたモデルパラメータとプロンプトテンプレートに依存しています。', + title: '補完アプリ API', + info: '記事、要約、翻訳などの高品質なテキスト生成には、ユーザーの入力を使用した補完メッセージ API を使用します。テキスト生成は、Dify Prompt Engineering で設定されたモデルパラメータとプロンプトテンプレートに依存しています。', createCompletionApi: '補完メッセージの作成', createCompletionApiTip: '質疑応答モードをサポートするために、補完メッセージを作成します。', - inputsTips: '(オプション)Prompt Engの変数に対応するキーと値のペアとしてユーザー入力フィールドを提供します。キーは変数名で、値はパラメータの値です。フィールドのタイプがSelectの場合、送信される値は事前に設定された選択肢のいずれかである必要があります。', + inputsTips: '(オプション)Prompt Eng の変数に対応するキーと値のペアとしてユーザー入力フィールドを提供します。キーは変数名で、値はパラメータの値です。フィールドのタイプが Select の場合、送信される値は事前に設定された選択肢のいずれかである必要があります。', queryTips: 'ユーザーの入力テキスト内容。', blocking: 'ブロッキングタイプで、実行が完了して結果が返されるまで待機します。(処理が長い場合、リクエストは中断される場合があります)', streaming: 'ストリーミングの返却。SSE(Server-Sent Events)に基づいたストリーミングの返却の実装。', messageFeedbackApi: 'メッセージフィードバック(いいね)', messageFeedbackApiTip: 'エンドユーザーの代わりに受信したメッセージを「いいね」または「いいね」で評価します。このデータはログ&注釈ページで表示され、将来のモデルの微調整に使用されます。', - messageIDTip: 'メッセージID', - ratingTip: 'いいねまたはいいね、nullは元に戻す', + messageIDTip: 'メッセージ ID', + ratingTip: 'いいねまたはいいね、null は元に戻す', parametersApi: 'アプリケーションパラメータ情報の取得', parametersApiTip: '変数名、フィールド名、タイプ、デフォルト値を含む設定済みの入力パラメータを取得します。通常、これらのフィールドをフォームに表示したり、クライアントの読み込み後にデフォルト値を入力したりするために使用されます。', }, chatMode: { - title: 'チャットアプリAPI', - info: '質疑応答形式を使用した多目的の対話型アプリケーションには、チャットメッセージAPIを呼び出して対話を開始します。返されたconversation_idを渡すことで、継続的な会話を維持します。応答パラメータとテンプレートは、Dify Prompt Engの設定に依存します。', + title: 'チャットアプリ API', + info: '質疑応答形式を使用した多目的の対話型アプリケーションには、チャットメッセージ API を呼び出して対話を開始します。返された conversation_id を渡すことで、継続的な会話を維持します。応答パラメータとテンプレートは、Dify Prompt Eng の設定に依存します。', createChatApi: 'チャットメッセージの作成', createChatApiTip: '新しい会話メッセージを作成するか、既存の対話を継続します。', - inputsTips: '(オプション)Prompt Engの変数に対応するキーと値のペアとしてユーザー入力フィールドを提供します。キーは変数名で、値はパラメータの値です。フィールドのタイプがSelectの場合、送信される値は事前に設定された選択肢のいずれかである必要があります。', + inputsTips: '(オプション)Prompt Eng の変数に対応するキーと値のペアとしてユーザー入力フィールドを提供します。キーは変数名で、値はパラメータの値です。フィールドのタイプが Select の場合、送信される値は事前に設定された選択肢のいずれかである必要があります。', queryTips: 'ユーザーの入力/質問内容', blocking: 'ブロッキングタイプで、実行が完了して結果が返されるまで待機します。(処理が長い場合、リクエストは中断される場合があります)', streaming: 'ストリーミングの返却。SSE(Server-Sent Events)に基づいたストリーミングの返却の実装。', - conversationIdTip: '(オプション)会話ID:初回の会話の場合は空白のままにしておき、継続する場合はコンテキストからconversation_idを渡します。', + conversationIdTip: '(オプション)会話 ID:初回の会話の場合は空白のままにしておき、継続する場合はコンテキストから conversation_id を渡します。', messageFeedbackApi: 'メッセージ端末ユーザーフィードバック、いいね', messageFeedbackApiTip: 'エンドユーザーの代わりに受信したメッセージを「いいね」または「いいね」で評価します。このデータはログ&注釈ページで表示され、将来のモデルの微調整に使用されます。', - messageIDTip: 'メッセージID', - ratingTip: 'いいねまたはいいね、nullは元に戻す', + messageIDTip: 'メッセージ ID', + ratingTip: 'いいねまたはいいね、null は元に戻す', chatMsgHistoryApi: 'チャット履歴メッセージの取得', chatMsgHistoryApiTip: '最初のページは最新の「limit」バーを返します。逆順です。', - chatMsgHistoryConversationIdTip: '会話ID', - chatMsgHistoryFirstId: '現在のページの最初のチャットレコードのID。デフォルトはなし。', - chatMsgHistoryLimit: '1回のリクエストで返されるチャットの数', + chatMsgHistoryConversationIdTip: '会話 ID', + chatMsgHistoryFirstId: '現在のページの最初のチャットレコードの ID。デフォルトはなし。', + chatMsgHistoryLimit: '1 回のリクエストで返されるチャットの数', conversationsListApi: '会話リストの取得', - conversationsListApiTip: '現在のユーザーのセッションリストを取得します。デフォルトでは、最後の20のセッションが返されます。', - conversationsListFirstIdTip: '現在のページの最後のレコードのID、デフォルトはなし。', - conversationsListLimitTip: '1回のリクエストで返されるチャットの数', + conversationsListApiTip: '現在のユーザーのセッションリストを取得します。デフォルトでは、最後の 20 のセッションが返されます。', + conversationsListFirstIdTip: '現在のページの最後のレコードの ID、デフォルトはなし。', + conversationsListLimitTip: '1 回のリクエストで返されるチャットの数', conversationRenamingApi: '会話の名前変更', conversationRenamingApiTip: '会話の名前を変更します。名前はマルチセッションクライアントインターフェースに表示されます。', conversationRenamingNameTip: '新しい名前', diff --git a/web/i18n/ja-JP/app-debug.ts b/web/i18n/ja-JP/app-debug.ts index 350d58d60a..cc07a6d8f6 100644 --- a/web/i18n/ja-JP/app-debug.ts +++ b/web/i18n/ja-JP/app-debug.ts @@ -5,12 +5,12 @@ const translation = { }, orchestrate: 'オーケストレーション', promptMode: { - simple: 'エキスパートモードに切り替えて、PROMPT全体を編集します', + simple: 'エキスパートモードに切り替えて、PROMPT 全体を編集します', advanced: 'エキスパートモード', switchBack: '基本モードに戻る', advancedWarning: { - title: 'エキスパートモードに切り替えました。PROMPTを変更すると、基本モードに戻ることはできません。', - description: 'エキスパートモードでは、PROMPT全体を編集できます。', + title: 'エキスパートモードに切り替えました。PROMPT を変更すると、基本モードに戻ることはできません。', + description: 'エキスパートモードでは、PROMPT 全体を編集できます。', learnMore: '詳細はこちら', ok: 'OK', }, @@ -33,14 +33,14 @@ const translation = { userAction: 'ユーザー', }, notSetAPIKey: { - title: 'LLMプロバイダーキーが設定されていません', + title: 'LLM プロバイダーキーが設定されていません', trailFinished: 'トライアル終了', - description: 'LLMプロバイダーキーが設定されていません。デバッグする前に設定する必要があります。', + description: 'LLM プロバイダーキーが設定されていません。デバッグする前に設定する必要があります。', settingBtn: '設定に移動', }, trailUseGPT4Info: { - title: '現在、gpt-4はサポートされていません', - description: 'gpt-4を使用するには、APIキーを設定してください。', + title: '現在、gpt-4 はサポートされていません', + description: 'gpt-4 を使用するには、API キーを設定してください。', }, feature: { groupChat: { @@ -52,12 +52,12 @@ const translation = { }, conversationOpener: { title: '会話の開始', - description: 'チャットアプリでは、AIがユーザーに最初にアクティブに話しかける最初の文は、通常、歓迎メッセージとして使用されます。', + description: 'チャットアプリでは、AI がユーザーに最初にアクティブに話しかける最初の文は、通常、歓迎メッセージとして使用されます。', }, suggestedQuestionsAfterAnswer: { title: 'フォローアップ', description: '次の質問の提案を設定すると、ユーザーにより良いチャットが提供されます。', - resDes: 'ユーザーの次の質問に関する3つの提案。', + resDes: 'ユーザーの次の質問に関する 3 つの提案。', tryToAsk: '質問してみてください', }, moreLikeThis: { @@ -128,7 +128,7 @@ const translation = { }, tools: { title: 'ツール', - tips: 'ツールは、ユーザー入力または変数をリクエストパラメーターとして使用して外部データをコンテキストとしてクエリするための標準的なAPI呼び出し方法を提供します。', + tips: 'ツールは、ユーザー入力または変数をリクエストパラメーターとして使用して外部データをコンテキストとしてクエリするための標準的な API 呼び出し方法を提供します。', toolsInUse: '{{count}} 個のツールが使用中', modal: { title: 'ツール', @@ -162,7 +162,7 @@ const translation = { }, moderation: { title: 'コンテンツのモデレーション', - description: 'モデレーションAPIを使用するか、機密語リストを維持することで、モデルの出力を安全にします。', + description: 'モデレーション API を使用するか、機密語リストを維持することで、モデルの出力を安全にします。', contentEnableLabel: 'モデレート・コンテンツを有効にする', allEnabled: '入力/出力コンテンツが有効になっています', inputEnabled: '入力コンテンツが有効になっています', @@ -171,16 +171,16 @@ const translation = { title: 'コンテンツのモデレーション設定', provider: { title: 'プロバイダ', - openai: 'OpenAIモデレーション', + openai: 'OpenAI モデレーション', openaiTip: { - prefix: 'OpenAIモデレーションには、', - suffix: 'にOpenAI APIキーが設定されている必要があります。', + prefix: 'OpenAI モデレーションには、', + suffix: 'に OpenAI API キーが設定されている必要があります。', }, keywords: 'キーワード', }, keywords: { - tip: '1行ごとに1つ、行区切りで入力してください。1行あたり最大100文字。', - placeholder: '1行ごとに、行区切りで入力してください', + tip: '1 行ごとに 1 つ、行区切りで入力してください。1 行あたり最大 100 文字。', + placeholder: '1 行ごとに、行区切りで入力してください', line: '行', }, content: { @@ -188,14 +188,14 @@ const translation = { output: '出力コンテンツをモデレート', preset: 'プリセット返信', placeholder: 'ここにプリセット返信の内容を入力', - condition: '少なくとも1つの入力および出力コンテンツをモデレートする', - fromApi: 'プリセット返信はAPIによって返されます', + condition: '少なくとも 1 つの入力および出力コンテンツをモデレートする', + fromApi: 'プリセット返信は API によって返されます', errorMessage: 'プリセット返信は空にできません', - supportMarkdown: 'Markdownがサポートされています', + supportMarkdown: 'Markdown がサポートされています', }, openaiNotConfig: { - before: 'OpenAIモデレーションには、', - after: 'にOpenAI APIキーが設定されている必要があります。', + before: 'OpenAI モデレーションには、', + after: 'に OpenAI API キーが設定されている必要があります。', }, }, }, @@ -214,13 +214,13 @@ const translation = { modalTitle: '画像アップロード設置', }, bar: { - empty: 'Webアプリのユーザーエクスペリアンスを強化させる機能を有効にする', + empty: 'Web アプリのユーザーエクスペリアンスを強化させる機能を有効にする', enableText: '有効な機能', manage: '管理', }, documentUpload: { title: 'ドキュメント', - description: 'ドキュメント機能を有効にすると、AIモデルがファイルを処理し、その内容に基づいて質問に回答できるようになります。', + description: 'ドキュメント機能を有効にすると、AI モデルがファイルを処理し、その内容に基づいて質問に回答できるようになります。', }, }, codegen: { @@ -228,7 +228,7 @@ const translation = { description: 'コードジェネレーターは、設定されたモデルを使用して指示に基づいて高品質なコードを生成します。明確で詳細な指示を提供してください。', instruction: '指示', instructionPlaceholder: '生成したいコードの詳細な説明を入力してください。', - noDataLine1: '左側に使用例を記入してください,', + noDataLine1: '左側に使用例を記入してください,', noDataLine2: 'コードのプレビューがこちらに表示されます。', generate: '生成', generatedCodeTitle: '生成されたコード', @@ -247,7 +247,7 @@ const translation = { instructionPlaceHolder: '具体的で明確な指示を入力してください。', generate: '生成', resTitle: '生成されたプロンプト', - noDataLine1: '左側に使用例を記入してください,', + noDataLine1: '左側に使用例を記入してください,', noDataLine2: 'オーケストレーションのプレビューがこちらに表示されます。', apply: '適用', noData: '左側にユースケースを入力すると、こちらでプレビューができます。', @@ -276,12 +276,12 @@ const translation = { instruction: 'ユーザーが簡単に旅行計画を立てられるように設計されたツール', }, SQLSorcerer: { - name: 'SQLソーサラー', - instruction: '日常言語をSQLクエリに変換する', + name: 'SQL ソーサラー', + instruction: '日常言語を SQL クエリに変換する', }, GitGud: { name: 'Git gud', - instruction: 'ユーザーが記述したバージョン管理アクションに対応するGitコマンドを生成する', + instruction: 'ユーザーが記述したバージョン管理アクションに対応する Git コマンドを生成する', }, meetingTakeaways: { name: '会議の要点', @@ -298,7 +298,7 @@ const translation = { message: '変更が破棄され、最後に公開された構成が復元されます。', }, errorMessage: { - nameOfKeyRequired: 'キーの名前: {{key}} が必要です', + nameOfKeyRequired: 'キーの名前:{{key}} が必要です', valueOfVarRequired: '{{key}} の値は空にできません', queryRequired: 'リクエストテキストが必要です。', waitForResponse: '前のメッセージへの応答が完了するまでお待ちください。', @@ -309,7 +309,7 @@ const translation = { }, chatSubTitle: 'プロンプト', completionSubTitle: '接頭辞プロンプト', - promptTip: 'プロンプトは、AIの応答を指示と制約で誘導します。 {{input}} のような変数を挿入します。このプロンプトはユーザーには表示されません。', + promptTip: 'プロンプトは、AI の応答を指示と制約で誘導します。 {{input}} のような変数を挿入します。このプロンプトはユーザーには表示されません。', formattingChangedTitle: '書式が変更されました', formattingChangedText: '書式を変更すると、デバッグ領域がリセットされます。よろしいですか?', variableTitle: '変数', @@ -327,7 +327,7 @@ const translation = { }, varKeyError: { canNoBeEmpty: '{{key}} は必須です', - tooLong: '{{key}} が長すぎます。30文字を超えることはできません', + tooLong: '{{key}} が長すぎます。30 文字を超えることはできません', notValid: '{{key}} が無効です。文字、数字、アンダースコアのみを含めることができます', notStartWithNumber: '{{key}} は数字で始めることはできません', keyAlreadyExists: '{{key}} はすでに存在します', @@ -354,7 +354,7 @@ const translation = { 'maxLength': '最大長', 'options': 'オプション', 'addOption': 'オプションを追加', - 'apiBasedVar': 'APIベースの変数', + 'apiBasedVar': 'API ベースの変数', 'varName': '変数名', 'labelName': 'ラベル名', 'inputPlaceholder': '入力してください', @@ -376,7 +376,7 @@ const translation = { custom: { name: '他のファイルタイプ', description: '他のファイルタイプを指定する。', - createPlaceholder: '+ 拡張子, 例:.doc', + createPlaceholder: '+ 拡張子,例:.doc', }, }, 'uploadFileTypes': 'アップロードされたファイルのタイプ', @@ -388,7 +388,7 @@ const translation = { varNameRequired: '変数名は必須です', labelNameRequired: 'ラベル名は必須です', varNameCanBeRepeat: '変数名は繰り返すことができません', - atLeastOneOption: '少なくとも1つのオプションが必要です', + atLeastOneOption: '少なくとも 1 つのオプションが必要です', optionRepeat: '繰り返しオプションがあります', }, }, @@ -473,10 +473,10 @@ const translation = { title: 'マルチパスリトリーバル', description: 'ユーザーの意図に基づいて、すべてのナレッジをクエリし、複数のソースから関連するテキストを取得し、再順位付け後、ユーザークエリに最適な結果を選択します。再順位付けモデル API の構成が必要です。', }, - embeddingModelRequired: 'Embeddingモデルが設定されていない', + embeddingModelRequired: 'Embedding モデルが設定されていない', rerankModelRequired: '再順位付けモデルが必要です', params: 'パラメータ', - top_k: 'トップK', + top_k: 'トップ K', top_kTip: 'ユーザーの質問に最も類似したチャンクをフィルタリングするために使用されます。システムは、選択したモデルの max_tokens に応じて、動的に Top K の値を調整します。', score_threshold: 'スコア閾値', score_thresholdTip: 'チャンクフィルタリングの類似性閾値を設定するために使用されます。', @@ -518,7 +518,7 @@ const translation = { promptPlaceholder: 'ここにプロンプトを入力してください', tools: { name: 'ツール', - description: 'ツールを使用すると、インターネットの検索や科学的計算など、LLMの機能を拡張できます', + description: 'ツールを使用すると、インターネットの検索や科学的計算など、LLM の機能を拡張できます', enabled: '有効', }, }, diff --git a/web/i18n/ja-JP/app-log.ts b/web/i18n/ja-JP/app-log.ts index d4553e830c..43a6fb9151 100644 --- a/web/i18n/ja-JP/app-log.ts +++ b/web/i18n/ja-JP/app-log.ts @@ -1,6 +1,6 @@ const translation = { title: 'ログ', - description: 'ログは、アプリケーションの実行状態を記録します。ユーザーの入力やAIの応答などが含まれます。', + description: 'ログは、アプリケーションの実行状態を記録します。ユーザーの入力や AI の応答などが含まれます。', dateTimeFormat: 'MM/DD/YYYY hh:mm A', table: { header: { @@ -29,13 +29,13 @@ const translation = { noOutput: '出力がありません', element: { title: '誰かいますか?', - content: 'ここでは、エンドユーザーとAIアプリケーション間の相互作用を観察し、注釈を付けることで、AIの精度を継続的に向上させます。Webアプリを共有またはテストしてみて、このページに戻ってください。', + content: 'ここでは、エンドユーザーと AI アプリケーション間の相互作用を観察し、注釈を付けることで、AI の精度を継続的に向上させます。Web アプリを共有またはテストしてみて、このページに戻ってください。', }, }, }, detail: { time: '時間', - conversationId: '会話ID', + conversationId: '会話 ID', promptTemplate: 'プロンプトテンプレート', promptTemplateBeforeChat: 'チャット前のプロンプトテンプレート・システムメッセージとして', annotationTip: '{{user}} によってマークされた改善', @@ -48,7 +48,7 @@ const translation = { dislike: 'いいね解除', addAnnotation: '改善を追加', editAnnotation: '改善を編集', - annotationPlaceholder: '将来のモデルの微調整やテキスト生成品質の継続的改善のためにAIが返信することを期待する答えを入力してください。', + annotationPlaceholder: '将来のモデルの微調整やテキスト生成品質の継続的改善のために AI が返信することを期待する答えを入力してください。', }, variables: '変数', uploadImages: 'アップロードされた画像', @@ -57,10 +57,10 @@ const translation = { filter: { period: { today: '今日', - last7days: '過去7日間', - last4weeks: '過去4週間', - last3months: '過去3ヶ月', - last12months: '過去12ヶ月', + last7days: '過去 7 日間', + last4weeks: '過去 4 週間', + last3months: '過去 3 ヶ月', + last12months: '過去 12 ヶ月', monthToDate: '月初から今日まで', quarterToDate: '四半期初から今日まで', yearToDate: '年初から今日まで', diff --git a/web/i18n/ja-JP/app-overview.ts b/web/i18n/ja-JP/app-overview.ts index 3b0505b0de..d948bc3b28 100644 --- a/web/i18n/ja-JP/app-overview.ts +++ b/web/i18n/ja-JP/app-overview.ts @@ -1,9 +1,9 @@ const translation = { welcome: { firstStepTip: 'はじめるには、', - enterKeyTip: '以下にOpenAI APIキーを入力してください', - getKeyTip: 'OpenAIダッシュボードからAPIキーを取得してください', - placeholder: 'OpenAI APIキー(例:sk-xxxx)', + enterKeyTip: '以下に OpenAI API キーを入力してください', + getKeyTip: 'OpenAI ダッシュボードから API キーを取得してください', + placeholder: 'OpenAI API キー(例:sk-xxxx)', }, apiKeyInfo: { cloud: { @@ -12,7 +12,7 @@ const translation = { description: 'トライアルクォータはテスト用に提供されます。トライアルクォータのコールが使い切られる前に、独自のモデルプロバイダを設定するか、追加のクォータを購入してください。', }, exhausted: { - title: 'トライアルクォータが使い切れました。APIキーを設定してください。', + title: 'トライアルクォータが使い切れました。API キーを設定してください。', description: 'トライアルクォータが使い切れました。独自のモデルプロバイダを設定するか、追加のクォータを購入してください。', }, }, @@ -25,36 +25,36 @@ const translation = { callTimes: 'コール回数', usedToken: '使用済みトークン', setAPIBtn: 'モデルプロバイダの設定へ', - tryCloud: 'またはDifyのクラウドバージョンを無料見積もりでお試しください', + tryCloud: 'または Dify のクラウドバージョンを無料見積もりでお試しください', }, overview: { title: '概要', appInfo: { - explanation: '使いやすいAI Webアプリ', - accessibleAddress: '公開URL', + explanation: '使いやすい AI Web アプリ', + accessibleAddress: '公開 URL', preview: 'プレビュー', regenerate: '再生成', - regenerateNotice: '公開URLを再生成しますか?', - preUseReminder: '続行する前にWebアプリを有効にしてください。', + regenerateNotice: '公開 URL を再生成しますか?', + preUseReminder: '続行する前に Web アプリを有効にしてください。', settings: { entry: '設定', - title: 'Webアプリの設定', - webName: 'Webアプリの名前', - webDesc: 'Webアプリの説明', + title: 'Web アプリの設定', + webName: 'Web アプリの名前', + webDesc: 'Web アプリの説明', webDescTip: 'このテキストはクライアント側に表示され、アプリケーションの使用方法の基本的なガイダンスを提供します。', - webDescPlaceholder: 'Webアプリの説明を入力してください', + webDescPlaceholder: 'Web アプリの説明を入力してください', language: '言語', workflow: { title: 'ワークフローステップ', show: '表示', hide: '非表示', subTitle: 'ワークフローの詳細', - showDesc: 'Webアプリでワークフローの詳細を表示または非表示にする', + showDesc: 'Web アプリでワークフローの詳細を表示または非表示にする', }, chatColorTheme: 'チャットボットのカラーテーマ', chatColorThemeDesc: 'チャットボットのカラーテーマを設定します', chatColorThemeInverted: '反転', - invalidHexMessage: '無効な16進数値', + invalidHexMessage: '無効な 16 進数値', invalidPrivacyPolicy: '無効なプライバシーポリシーのリンクです。http または https で始まる有効なリンクを使用してください', more: { entry: 'その他の設定を表示', @@ -62,18 +62,18 @@ const translation = { copyRightPlaceholder: '著作者または組織名を入力してください', privacyPolicy: 'プライバシーポリシー', privacyPolicyPlaceholder: 'プライバシーポリシーリンクを入力してください', - privacyPolicyTip: '訪問者がアプリケーションが収集するデータを理解し、Difyのプライバシーポリシーを参照できるようにします。', + privacyPolicyTip: '訪問者がアプリケーションが収集するデータを理解し、Dify のプライバシーポリシーを参照できるようにします。', customDisclaimer: 'カスタム免責事項', customDisclaimerPlaceholder: '免責事項を入力してください', customDisclaimerTip: 'アプリケーションの使用に関する免責事項を提供します。', copyrightTooltip: 'プロフェッショナルプラン以上にアップグレードしてください', - copyrightTip: 'Webアプリに著作権情報を表示する', + copyrightTip: 'Web アプリに著作権情報を表示する', }, sso: { - title: 'WebアプリのSSO', - tooltip: '管理者に問い合わせて、WebアプリのSSOを有効にします', - label: 'SSO認証', - description: 'すべてのユーザーは、Webアプリを使用する前にSSOでログインする必要があります', + title: 'Web アプリの SSO', + tooltip: '管理者に問い合わせて、Web アプリの SSO を有効にします', + label: 'SSO 認証', + description: 'すべてのユーザーは、Web アプリを使用する前に SSO でログインする必要があります', }, modalTip: 'クライアント側の Web アプリ設定。', }, @@ -81,45 +81,45 @@ const translation = { entry: '埋め込み', title: 'ウェブサイトに埋め込む', explanation: 'チャットアプリをウェブサイトに埋め込む方法を選択します。', - iframe: 'ウェブサイトの任意の場所にチャットアプリを追加するには、このiframeをHTMLコードに追加してください。', - scripts: 'ウェブサイトの右下にチャットアプリを追加するには、このコードをHTMLに追加してください。', - chromePlugin: 'Dify Chatbot Chrome拡張機能をインストール', + iframe: 'ウェブサイトの任意の場所にチャットアプリを追加するには、この iframe を HTML コードに追加してください。', + scripts: 'ウェブサイトの右下にチャットアプリを追加するには、このコードを HTML に追加してください。', + chromePlugin: 'Dify Chatbot Chrome 拡張機能をインストール', copied: 'コピーしました', copy: 'コピー', }, qrcode: { - title: '共有用QRコード', + title: '共有用 QR コード', scan: 'アプリケーションの共有をスキャン', - download: 'QRコードをダウンロード', + download: 'QR コードをダウンロード', }, customize: { way: '方法', entry: 'カスタマイズ', - title: 'AI Webアプリのカスタマイズ', - explanation: 'シナリオとスタイルのニーズに合わせてWebアプリのフロントエンドをカスタマイズできます。', + title: 'AI Web アプリのカスタマイズ', + explanation: 'シナリオとスタイルのニーズに合わせて Web アプリのフロントエンドをカスタマイズできます。', way1: { - name: 'クライアントコードをフォークして修正し、Vercelにデプロイします(推奨)', + name: 'クライアントコードをフォークして修正し、Vercel にデプロイします(推奨)', step1: 'クライアントコードをフォークして修正します', - step1Tip: 'ここをクリックしてソースコードをGitHubアカウントにフォークし、コードを修正します', + step1Tip: 'ここをクリックしてソースコードを GitHub アカウントにフォークし、コードを修正します', step1Operation: 'Dify-WebClient', - step2: 'Vercelにデプロイします', - step2Tip: 'ここをクリックしてリポジトリをVercelにインポートし、デプロイします', + step2: 'Vercel にデプロイします', + step2Tip: 'ここをクリックしてリポジトリを Vercel にインポートし、デプロイします', step2Operation: 'リポジトリをインポート', step3: '環境変数を設定します', - step3Tip: 'Vercelに次の環境変数を追加します', + step3Tip: 'Vercel に次の環境変数を追加します', }, way2: { - name: 'クライアントサイドのコードを記述してAPIを呼び出し、サーバーにデプロイします', + name: 'クライアントサイドのコードを記述して API を呼び出し、サーバーにデプロイします', operation: 'ドキュメント', }, }, launch: '発射', }, apiInfo: { - title: 'バックエンドサービスAPI', + title: 'バックエンドサービス API', explanation: 'あなたのアプリケーションに簡単に統合できます', - accessibleAddress: 'サービスAPIエンドポイント', - doc: 'APIリファレンス', + accessibleAddress: 'サービス API エンドポイント', + doc: 'API リファレンス', }, status: { running: '稼働中', @@ -132,15 +132,15 @@ const translation = { tokenPS: 'トークン/秒', totalMessages: { title: 'トータルメッセージ数', - explanation: '日次AIインタラクション数。', + explanation: '日次 AI インタラクション数。', }, totalConversations: { title: '総会話数', - explanation: '日次AI会話数;プロンプトエンジニアリング/デバッグは除外。', + explanation: '日次 AI 会話数;プロンプトエンジニアリング/デバッグは除外。', }, activeUsers: { title: 'アクティブユーザー数', - explanation: 'AIとのQ&Aに参加しているユニークユーザー数;工学的/デバッグ目的のプロンプトは除外されます。', + explanation: 'AI との Q&A に参加しているユニークユーザー数;工学的/デバッグ目的のプロンプトは除外されます。', }, tokenUsage: { title: 'トークン使用量', @@ -149,7 +149,7 @@ const translation = { }, avgSessionInteractions: { title: '平均セッションインタラクション数', - explanation: 'ユーザーとAIの連続的なコミュニケーション数;対話型アプリケーション向け。', + explanation: 'ユーザーと AI の連続的なコミュニケーション数;対話型アプリケーション向け。', }, avgUserInteractions: { title: '平均ユーザーインタラクション数', @@ -157,15 +157,15 @@ const translation = { }, userSatisfactionRate: { title: 'ユーザー満足度率', - explanation: '1,000件のメッセージあたりの「いいね」の数。これは、ユーザーが非常に満足している回答の割合を示します。', + explanation: '1,000 件のメッセージあたりの「いいね」の数。これは、ユーザーが非常に満足している回答の割合を示します。', }, avgResponseTime: { title: '平均応答時間', - explanation: 'AIが処理/応答する時間(ミリ秒);テキストベースのアプリケーション向け。', + explanation: 'AI が処理/応答する時間(ミリ秒);テキストベースのアプリケーション向け。', }, tps: { title: 'トークン出力速度', - explanation: 'LLMのパフォーマンスを測定します。リクエストの開始から出力の完了までのLLMのトークン出力速度を数えます。', + explanation: 'LLM のパフォーマンスを測定します。リクエストの開始から出力の完了までの LLM のトークン出力速度を数えます。', }, }, } diff --git a/web/i18n/ja-JP/app.ts b/web/i18n/ja-JP/app.ts index 283dd0f003..b4fc8d4d82 100644 --- a/web/i18n/ja-JP/app.ts +++ b/web/i18n/ja-JP/app.ts @@ -19,10 +19,10 @@ const translation = { exportFailed: 'DSL のエクスポートに失敗しました。', importDSL: 'DSL ファイルをインポート', createFromConfigFile: 'DSL ファイルから作成する', - importFromDSL: 'DSLからインポート', - importFromDSLFile: 'DSLファイルから', - importFromDSLUrl: 'URLから', - importFromDSLUrlPlaceholder: 'DSLリンクをここに貼り付けます', + importFromDSL: 'DSL からインポート', + importFromDSLFile: 'DSL ファイルから', + importFromDSLUrl: 'URL から', + importFromDSLUrlPlaceholder: 'DSL リンクをここに貼り付けます', deleteAppConfirmTitle: 'このアプリを削除しますか?', deleteAppConfirmContent: 'アプリを削除すると、元に戻すことはできません。他のユーザーはもはやこのアプリにアクセスできず、すべてのプロンプトの設定とログが永久に削除されます。', @@ -73,11 +73,11 @@ const translation = { appCreateFailed: 'アプリの作成に失敗しました', Confirm: '確認する', caution: '注意', - appCreateDSLErrorPart2: '続行しますか?', - appCreateDSLErrorPart4: 'システムがサポートするDSLバージョン:', - appCreateDSLErrorPart3: '現在のアプリケーションの DSL バージョン:', + appCreateDSLErrorPart2: '続行しますか?', + appCreateDSLErrorPart4: 'システムがサポートする DSL バージョン:', + appCreateDSLErrorPart3: '現在のアプリケーションの DSL バージョン:', appCreateDSLErrorTitle: 'バージョンの非互換性', - appCreateDSLWarning: '注意:DSLのバージョンの違いは、特定の機能に影響を与える可能性があります', + appCreateDSLWarning: '注意:DSL のバージョンの違いは、特定の機能に影響を与える可能性があります', appCreateDSLErrorPart1: 'DSL バージョンに大きな違いが検出されました。インポートを強制すると、アプリケーションが誤動作する可能性があります。', optional: '随意', forBeginners: '初心者向けの基本的なアプリタイプ', @@ -95,11 +95,11 @@ const translation = { forAdvanced: '上級ユーザー向け', chooseAppType: 'アプリタイプを選択', learnMore: '詳細情報', - noIdeaTip: 'アイデアがありませんか?テンプレートをご覧ください', - chatbotShortDescription: '簡単なセットアップのLLMベースのチャットボット', - chatbotUserDescription: '簡単な設定でLLMベースのチャットボットを迅速に構築します。Chatflowは後で切り替えることができます。', - workflowUserDescription: 'ドラッグ&ドロップの簡易性で自律型AIワークフローを視覚的に構築', - completionUserDescription: '簡単な構成でテキスト生成タスク用のAIアシスタントをすばやく構築します。', + noIdeaTip: 'アイデアがありませんか?テンプレートをご覧ください', + chatbotShortDescription: '簡単なセットアップの LLM ベースのチャットボット', + chatbotUserDescription: '簡単な設定で LLM ベースのチャットボットを迅速に構築します。Chatflow は後で切り替えることができます。', + workflowUserDescription: 'ドラッグ&ドロップの簡易性で自律型 AI ワークフローを視覚的に構築', + completionUserDescription: '簡単な構成でテキスト生成タスク用の AI アシスタントをすばやく構築します。', }, editApp: '情報を編集する', editAppTitle: 'アプリ情報を編集する', @@ -129,7 +129,7 @@ const translation = { }, tracing: { title: 'アプリのパフォーマンスの追跡', - description: 'サードパーティのLLMOpsサービスとトレースアプリケーションのパフォーマンス設定を行います。', + description: 'サードパーティの LLMOps サービスとトレースアプリケーションのパフォーマンス設定を行います。', config: '設定', view: '見る', collapse: '折りたたむ', @@ -138,7 +138,7 @@ const translation = { disabled: '無効しました', disabledTip: 'まずはサービスの設定から始めましょう。', enabled: '有効しました', - tracingDescription: 'LLMの呼び出し、コンテキスト、プロンプト、HTTPリクエストなど、アプリケーション実行の全ての文脈をサードパーティのトレースプラットフォームで取り込みます。', + tracingDescription: 'LLM の呼び出し、コンテキスト、プロンプト、HTTP リクエストなど、アプリケーション実行の全ての文脈をサードパーティのトレースプラットフォームで取り込みます。', configProviderTitle: { configured: '設定しました', notConfigured: 'トレース機能を有効化するためには、サービスの設定が必要です。', @@ -146,11 +146,11 @@ const translation = { }, langsmith: { title: 'LangSmith', - description: 'LLMを利用したアプリケーションのライフサイクル全段階を支援する、オールインワンの開発者向けプラットフォームです。', + description: 'LLM を利用したアプリケーションのライフサイクル全段階を支援する、オールインワンの開発者向けプラットフォームです。', }, langfuse: { title: 'Langfuse', - description: 'トレース、評価、プロンプトの管理、そしてメトリクスを駆使して、LLMアプリケーションのデバッグや改善に役立てます。', + description: 'トレース、評価、プロンプトの管理、そしてメトリクスを駆使して、LLM アプリケーションのデバッグや改善に役立てます。', }, opik: { title: 'オピック', @@ -169,13 +169,13 @@ const translation = { }, weave: { title: '織る', - description: 'Weaveは、LLMアプリケーションを評価、テスト、および監視するためのオープンソースプラットフォームです。', + description: 'Weave は、LLM アプリケーションを評価、テスト、および監視するためのオープンソースプラットフォームです。', }, }, answerIcon: { - title: 'Webアプリアイコンを使用して🤖を置き換える', - description: '共有アプリケーションの中で Webアプリアイコンを使用して🤖を置き換えるかどうか', - descriptionInExplore: 'ExploreでWebアプリアイコンを使用して🤖を置き換えるかどうか', + title: 'Web アプリアイコンを使用して🤖を置き換える', + description: '共有アプリケーションの中で Web アプリアイコンを使用して🤖を置き換えるかどうか', + descriptionInExplore: 'Explore で Web アプリアイコンを使用して🤖を置き換えるかどうか', }, newAppFromTemplate: { sidebar: { @@ -198,17 +198,17 @@ const translation = { placeholder: 'アプリを選択...', }, structOutput: { - moreFillTip: '最大10レベルのネストを表示します', + moreFillTip: '最大 10 レベルのネストを表示します', required: '必須', - LLMResponse: 'LLMのレスポンス', + LLMResponse: 'LLM のレスポンス', configure: '設定', notConfiguredTip: '構造化出力が未設定です', structured: '構造化出力', - structuredTip: '構造化出力は、モデルが常に指定されたJSONスキーマに準拠した応答を生成することを保証する機能です。', + structuredTip: '構造化出力は、モデルが常に指定された JSON スキーマに準拠した応答を生成することを保証する機能です。', modelNotSupported: 'モデルが対応していません', modelNotSupportedTip: '現在のモデルはこの機能に対応しておらず、自動的にプロンプトインジェクションに切り替わります。', }, - accessControl: 'Webアプリアクセス制御', + accessControl: 'Web アプリアクセス制御', accessItemsDescription: { anyone: '誰でも Web アプリにアクセス可能', specific: '特定のグループまたはメンバーのみが Web アプリにアクセス可能', @@ -216,12 +216,12 @@ const translation = { }, accessControlDialog: { title: 'アクセス権限', - description: 'Webアプリのアクセス権限を設定します', + description: 'Web アプリのアクセス権限を設定します', accessLabel: '誰がアクセスできますか', accessItemsDescription: { - anyone: '誰でもWebアプリにアクセス可能です', - specific: '特定のグループやメンバーがWebアプリにアクセス可能です', - organization: '組織内の誰でもWebアプリにアクセス可能です', + anyone: '誰でも Web アプリにアクセス可能です', + specific: '特定のグループやメンバーが Web アプリにアクセス可能です', + organization: '組織内の誰でも Web アプリにアクセス可能です', }, accessItems: { anyone: 'すべてのユーザー', @@ -233,7 +233,7 @@ const translation = { members_one: '{{count}} メンバー', members_other: '{{count}} メンバー', noGroupsOrMembers: 'グループまたはメンバーが選択されていません', - webAppSSONotEnabledTip: 'Webアプリの認証方式設定については、企業管理者へご連絡ください。', + webAppSSONotEnabledTip: 'Web アプリの認証方式設定については、企業管理者へご連絡ください。', operateGroupAndMember: { searchPlaceholder: 'グループやメンバーを検索', allMembers: 'すべてのメンバー', @@ -243,11 +243,11 @@ const translation = { updateSuccess: '更新が成功しました', }, publishApp: { - title: 'Webアプリへのアクセス権', + title: 'Web アプリへのアクセス権', notSet: '未設定', - notSetDesc: '現在このWebアプリには誰もアクセスできません。権限を設定してください。', + notSetDesc: '現在この Web アプリには誰もアクセスできません。権限を設定してください。', }, - noAccessPermission: 'Webアプリにアクセス権限がありません', + noAccessPermission: 'Web アプリにアクセス権限がありません', } export default translation diff --git a/web/i18n/ja-JP/billing.ts b/web/i18n/ja-JP/billing.ts index b96a972504..ade390917d 100644 --- a/web/i18n/ja-JP/billing.ts +++ b/web/i18n/ja-JP/billing.ts @@ -16,11 +16,11 @@ const translation = { viewBilling: '請求とサブスクリプションの管理', buyPermissionDeniedTip: 'サブスクリプションするには、エンタープライズ管理者に連絡してください', plansCommon: { - title: 'あなたのAIの旅を支える価格設定', + title: 'あなたの AI の旅を支える価格設定', freeTrialTipPrefix: 'サインアップ後、', - freeTrialTip: '200回のOpenAIコールの無料に受け取る', + freeTrialTip: '200 回の OpenAI コールの無料に受け取る', freeTrialTipSuffix: '。クレジットカード不要', - yearlyTip: '10ヶ月分支払って、1年間楽しもう!', + yearlyTip: '10 ヶ月分支払って、1 年間楽しもう!', mostPopular: '人気', cloud: 'クラウドサービス', self: 'セルフホストサービス', @@ -53,11 +53,11 @@ const translation = { vectorSpace: '{{size}}の知識データストレージ', vectorSpaceTooltip: '高品質インデックスモードのドキュメントは、知識データストレージのリソースを消費します。知識データストレージの上限に達すると、新しいドキュメントはアップロードされません。', documentsRequestQuota: '{{count,number}}/分のナレッジ リクエストのレート制限', - documentsRequestQuotaTooltip: 'ナレッジベース内でワークスペースが1分間に実行できる操作の総数を示します。これには、データセットの作成、削除、更新、ドキュメントのアップロード、修正、アーカイブ、およびナレッジベースクエリが含まれます。この指標は、ナレッジベースリクエストのパフォーマンスを評価するために使用されます。例えば、Sandbox ユーザーが1分間に10回連続でヒットテストを実行した場合、そのワークスペースは次の1分間、データセットの作成、削除、更新、ドキュメントのアップロードや修正などの操作を一時的に実行できなくなります。', - apiRateLimit: 'APIレート制限', + documentsRequestQuotaTooltip: 'ナレッジベース内でワークスペースが 1 分間に実行できる操作の総数を示します。これには、データセットの作成、削除、更新、ドキュメントのアップロード、修正、アーカイブ、およびナレッジベースクエリが含まれます。この指標は、ナレッジベースリクエストのパフォーマンスを評価するために使用されます。例えば、Sandbox ユーザーが 1 分間に 10 回連続でヒットテストを実行した場合、そのワークスペースは次の 1 分間、データセットの作成、削除、更新、ドキュメントのアップロードや修正などの操作を一時的に実行できなくなります。', + apiRateLimit: 'API レート制限', apiRateLimitUnit: '{{count,number}}/日', - unlimitedApiRate: '無制限のAPIコール', - apiRateLimitTooltip: 'APIレート制限は、テキスト生成、チャットボット、ワークフロー、ドキュメント処理など、Dify API経由のすべてのリクエストに適用されます。', + unlimitedApiRate: '無制限の API コール', + apiRateLimitTooltip: 'API レート制限は、テキスト生成、チャットボット、ワークフロー、ドキュメント処理など、Dify API 経由のすべてのリクエストに適用されます。', documentProcessingPriority: '文書処理', documentProcessingPriorityUpgrade: 'より高い精度と高速な速度でデータを処理します。', priority: { @@ -76,16 +76,16 @@ const translation = { emailSupport: 'メールサポート', priorityEmail: '優先メール&チャットサポート', logoChange: 'ロゴ変更', - SSOAuthentication: 'SSO認証', + SSOAuthentication: 'SSO 認証', personalizedSupport: '個別サポート', - dedicatedAPISupport: '専用APIサポート', + dedicatedAPISupport: '専用 API サポート', customIntegration: 'カスタム統合とサポート', - ragAPIRequest: 'RAG APIリクエスト', + ragAPIRequest: 'RAG API リクエスト', bulkUpload: 'ドキュメントの一括アップロード', agentMode: 'エージェントモード', workflow: 'ワークフロー', - llmLoadingBalancing: 'LLMロードバランシング', - llmLoadingBalancingTooltip: 'APIレート制限を効果的に回避するために、モデルに複数のAPIキーを追加する。', + llmLoadingBalancing: 'LLM ロードバランシング', + llmLoadingBalancingTooltip: 'API レート制限を効果的に回避するために、モデルに複数の API キーを追加する。', }, comingSoon: '近日公開', member: 'メンバー', @@ -93,13 +93,13 @@ const translation = { messageRequest: { title: '{{count,number}}メッセージクレジット', titlePerMonth: '{{count,number}}メッセージクレジット/月', - tooltip: 'メッセージクレジットは、DifyでさまざまなOpenAIモデルを簡単にお試しいただくためのものです。モデルタイプに応じてクレジットが消費され、使い切った後はご自身のOpenAI APIキーに切り替えていただけます。', + tooltip: 'メッセージクレジットは、Dify でさまざまな OpenAI モデルを簡単にお試しいただくためのものです。モデルタイプに応じてクレジットが消費され、使い切った後はご自身の OpenAI API キーに切り替えていただけます。', }, annotatedResponse: { title: '{{count,number}}の注釈クォータ制限', tooltip: '手動での回答の編集と注釈により、カスタマイズ可能な高品質の質問応答機能をアプリに提供します。(チャットアプリのみに適用)', }, - ragAPIRequestTooltip: 'Difyのナレッジベース処理機能のみを呼び出すAPI呼び出しの数を指します。', + ragAPIRequestTooltip: 'Dify のナレッジベース処理機能のみを呼び出す API 呼び出しの数を指します。', receiptInfo: 'チームオーナーとチーム管理者のみが購読および請求情報を表示できます', }, plans: { @@ -124,11 +124,11 @@ const translation = { description: 'オープンソース版の無料プラン', price: '無料', btnText: 'コミュニティ版を始めましょう', - includesTitle: '無料機能:', + includesTitle: '無料機能:', features: [ 'パブリックリポジトリの全コア機能', 'シングルワークスペース', - 'Difyオープンソースライセンス準拠', + 'Dify オープンソースライセンス準拠', ], }, premium: { @@ -138,12 +138,12 @@ const translation = { price: '従量制', priceTip: 'クラウドマーケットプレイス基準', btnText: 'プレミアム版を取得', - includesTitle: 'コミュニティ版機能に加えて:', + includesTitle: 'コミュニティ版機能に加えて:', comingSoon: 'Microsoft Azure & Google Cloud 近日対応', features: [ 'クラウドプロバイダーによる自己管理', 'シングルワークスペース', - 'Webアプリのロゴ&ブランドカスタマイズ', + 'Web アプリのロゴ&ブランドカスタマイズ', '優先メール/チャットサポート', ], }, @@ -154,14 +154,14 @@ const translation = { price: 'カスタム', priceTip: '年間契約専用', btnText: '営業に相談', - includesTitle: 'プレミアム版機能に加えて:', + includesTitle: 'プレミアム版機能に加えて:', features: [ 'エンタープライズ向け拡張ソリューション', '商用ライセンス認可', '企業専用機能', 'マルチワークスペース管理', 'シングルサインオン(SSO)', - 'DifyパートナーによるSLA保証', + 'Dify パートナーによる SLA 保証', '高度なセキュリティ管理', '公式メンテナンス&アップデート', 'プロフェッショナル技術支援', diff --git a/web/i18n/ja-JP/common.ts b/web/i18n/ja-JP/common.ts index 882e00cec8..85f5863761 100644 --- a/web/i18n/ja-JP/common.ts +++ b/web/i18n/ja-JP/common.ts @@ -115,9 +115,9 @@ const translation = { temperature: '温度', temperatureTip: 'ランダム性を制御します:温度を下げると、よりランダムな完成品が得られます。温度がゼロに近づくにつれて、モデルは決定的で反復的になります。', - top_p: '上位P', + top_p: '上位 P', top_pTip: - 'ニュークリアスサンプリングによる多様性の制御:0.5は、すべての尤度加重オプションの半分が考慮されることを意味します。', + 'ニュークリアスサンプリングによる多様性の制御:0.5 は、すべての尤度加重オプションの半分が考慮されることを意味します。', presence_penalty: '存在ペナルティ', presence_penaltyTip: 'これまでのテキストにトークンが表示されるかどうかに基づいて、新しいトークンにいくらペナルティを科すかを制御します。\nモデルが新しいトピックについて話す可能性が高まります。', @@ -126,11 +126,11 @@ const translation = { 'これまでのテキスト内のトークンの既存の頻度に基づいて、新しいトークンにどれだけペナルティを科すかを制御します。\nモデルが同じ行を文字通りに繰り返す可能性が低くなります。', max_tokens: '最大トークン', max_tokensTip: - '返信の最大長をトークン単位で制限するために使用されます。\n大きな値はプロンプトの単語、チャットログ、およびナレッジのために残されたスペースを制限する可能性があります。\nそれを2/3以下に設定することをお勧めします。\ngpt-4-1106-preview、gpt-4-vision-previewの最大トークン(入力128k出力4k)以下に設定することをお勧めします。', - maxTokenSettingTip: '最大トークン設定が高いため、プロンプト、クエリ、およびデータのスペースが制限される可能性があります。現在のモデルの最大トークンの80%以下に設定してください。', - setToCurrentModelMaxTokenTip: '最大トークンが現在のモデルの最大トークンの80%に更新されました {{maxToken}}.', + '返信の最大長をトークン単位で制限するために使用されます。\n大きな値はプロンプトの単語、チャットログ、およびナレッジのために残されたスペースを制限する可能性があります。\nそれを 2/3 以下に設定することをお勧めします。\ngpt-4-1106-preview、gpt-4-vision-preview の最大トークン(入力 128k 出力 4k)以下に設定することをお勧めします。', + maxTokenSettingTip: '最大トークン設定が高いため、プロンプト、クエリ、およびデータのスペースが制限される可能性があります。現在のモデルの最大トークンの 80% 以下に設定してください。', + setToCurrentModelMaxTokenTip: '最大トークンが現在のモデルの最大トークンの 80% に更新されました {{maxToken}}.', stop_sequences: '停止シーケンス', - stop_sequencesTip: 'APIが進行中のトークンの生成を停止する最大4つのシーケンス。返されたテキストには停止シーケンスは含まれません。', + stop_sequencesTip: 'API が進行中のトークンの生成を停止する最大 4 つのシーケンス。返されたテキストには停止シーケンスは含まれません。', stop_sequencesPlaceholder: 'シーケンスを入力してタブキーを押してください', }, tone: { @@ -150,9 +150,9 @@ const translation = { appDetail: 'アプリの詳細', account: 'アカウント', plugins: 'プラグイン', - pluginsTips: 'サードパーティのプラグインを統合するか、ChatGPT互換のAIプラグインを作成します。', + pluginsTips: 'サードパーティのプラグインを統合するか、ChatGPT 互換の AI プラグインを作成します。', datasets: 'ナレッジ', - datasetsTips: '近日公開:独自のテキストデータをインポートするか、Webhookを介してリアルタイムにデータを記述してLLMコンテキストを強化します。', + datasetsTips: '近日公開:独自のテキストデータをインポートするか、Webhook を介してリアルタイムにデータを記述して LLM コンテキストを強化します。', newApp: '新しいアプリ', newDataset: 'ナレッジの作成', tools: 'ツール', @@ -169,7 +169,7 @@ const translation = { communityFeedback: 'フィードバック', roadmap: 'ロードマップ', community: 'コミュニティ', - about: 'Difyについて', + about: 'Dify について', logout: 'ログアウト', github: 'GitHub', }, @@ -192,7 +192,7 @@ const translation = { provider: 'モデルプロバイダー', dataSource: 'データソース', plugin: 'プラグイン', - apiBasedExtension: 'API拡張', + apiBasedExtension: 'API 拡張', generalGroup: '一般', }, account: { @@ -206,7 +206,7 @@ const translation = { currentPassword: '現在のパスワード', newPassword: '新しいパスワード', confirmPassword: 'パスワードを確認', - notEqual: '2つのパスワードが異なります。', + notEqual: '2 つのパスワードが異なります。', langGeniusAccount: 'アカウント関連データ', langGeniusAccountTip: 'アカウントに関連するユーザーデータ。', editName: '名前を編集', @@ -223,7 +223,7 @@ const translation = { deleteLabel: '確認するには、以下にメールアドレスを入力してください', deletePlaceholder: 'メールアドレスを入力してください', verificationLabel: '認証コード', - verificationPlaceholder: '6桁のコードを貼り付けます', + verificationPlaceholder: '6 桁のコードを貼り付けます', permanentlyDeleteButton: 'アカウントを完全に削除', feedbackTitle: 'フィードバック', feedbackLabel: 'アカウントを削除した理由を教えてください。', @@ -260,7 +260,7 @@ const translation = { sendInvite: '招待を送る', invitedAsRole: '{{role}}ユーザーとして招待されました', invitationSent: '招待が送信されました', - invitationSentTip: '招待が送信され、彼らはDifyにサインインしてあなたのチームデータにアクセスできます。', + invitationSentTip: '招待が送信され、彼らは Dify にサインインしてあなたのチームデータにアクセスできます。', invitationLink: '招待リンク', failedInvitationEmails: '以下のユーザーは正常に招待されませんでした', ok: 'OK', @@ -277,9 +277,9 @@ const translation = { integrations: { connected: '接続済み', google: 'Google', - googleAccount: 'Googleアカウントでログイン', + googleAccount: 'Google アカウントでログイン', github: 'GitHub', - githubAccount: 'GitHubアカウントでログイン', + githubAccount: 'GitHub アカウントでログイン', connect: '接続', }, language: { @@ -287,29 +287,29 @@ const translation = { timezone: 'タイムゾーン', }, provider: { - apiKey: 'APIキー', - enterYourKey: 'ここにAPIキーを入力してください', - invalidKey: '無効なOpenAI APIキー', + apiKey: 'API キー', + enterYourKey: 'ここに API キーを入力してください', + invalidKey: '無効な OpenAI API キー', validatedError: '検証に失敗しました:', validating: 'キーの検証中...', - saveFailed: 'APIキーの保存に失敗しました', - apiKeyExceedBill: 'このAPI KEYには使用可能なクォータがありません。詳細は', + saveFailed: 'API キーの保存に失敗しました', + apiKeyExceedBill: 'この API KEY には使用可能なクォータがありません。詳細は', addKey: 'キーを追加', comingSoon: '近日公開', editKey: '編集', - invalidApiKey: '無効なAPIキー', + invalidApiKey: '無効な API キー', azure: { - apiBase: 'APIベース', - apiBasePlaceholder: 'Azure OpenAIエンドポイントのAPIベースURL。', - apiKey: 'APIキー', - apiKeyPlaceholder: 'ここにAPIキーを入力してください', - helpTip: 'Azure OpenAIサービスを学ぶ', + apiBase: 'API ベース', + apiBasePlaceholder: 'Azure OpenAI エンドポイントの API ベース URL。', + apiKey: 'API キー', + apiKeyPlaceholder: 'ここに API キーを入力してください', + helpTip: 'Azure OpenAI サービスを学ぶ', }, openaiHosted: { - openaiHosted: 'ホステッドOpenAI', + openaiHosted: 'ホステッド OpenAI', onTrial: 'トライアル中', exhausted: 'クォータが使い果たされました', - desc: 'Difyが提供するOpenAIホスティングサービスを使用すると、GPT-3.5などのモデルを使用できます。トライアルクォータが使い果たされる前に、他のモデルプロバイダを設定する必要があります。', + desc: 'Dify が提供する OpenAI ホスティングサービスを使用すると、GPT-3.5 などのモデルを使用できます。トライアルクォータが使い果たされる前に、他のモデルプロバイダを設定する必要があります。', callTimes: '通話回数', usedUp: 'トライアルクォータが使い果たされました。独自のモデルプロバイダを追加してください。', useYourModel: '現在、独自のモデルプロバイダを使用しています。', @@ -328,12 +328,12 @@ const translation = { }, anthropic: { using: '埋め込み機能は使用中です', - enableTip: 'Anthropicモデルを有効にするには、まずOpenAIまたはAzure OpenAIサービスにバインドする必要があります。', + enableTip: 'Anthropic モデルを有効にするには、まず OpenAI または Azure OpenAI サービスにバインドする必要があります。', notEnabled: '有効にされていません', - keyFrom: 'AnthropicからAPIキーを取得してください', + keyFrom: 'Anthropic から API キーを取得してください', }, encrypted: { - front: 'API KEYは', + front: 'API KEY は', back: '技術を使用して暗号化および保存されます。', }, }, @@ -361,8 +361,8 @@ const translation = { tip: '会話でのテキスト-to-音声入力に使用するデフォルトモデルを設定します。', }, rerankModel: { - key: 'Rerankモデル', - tip: 'Rerankモデルは、ユーザークエリとの意味的一致に基づいて候補文書リストを再配置し、意味的ランキングの結果を向上させます。', + key: 'Rerank モデル', + tip: 'Rerank モデルは、ユーザークエリとの意味的一致に基づいて候補文書リストを再配置し、意味的ランキングの結果を向上させます。', }, apiKey: 'API-キー', quota: 'クォータ', @@ -374,7 +374,7 @@ const translation = { tip: 'このモデルは削除されました。別のモデルを追加するか、別のモデルを選択してください。', emptyTip: '利用可能なモデルはありません', emptySetting: '設定に移動して構成してください', - rerankTip: 'Rerankモデルを設定してください', + rerankTip: 'Rerank モデルを設定してください', }, card: { quota: 'クォータ', @@ -385,17 +385,17 @@ const translation = { tokens: 'トークン', buyQuota: 'クォータを購入', priorityUse: '優先利用', - removeKey: 'APIキーを削除', + removeKey: 'API キーを削除', tip: '有料クォータは優先して使用されます。有料クォータを使用し終えた後、トライアルクォータが利用されます。', }, item: { deleteDesc: '{{modelName}}はシステムが推測するモデルとして利用されています。削除すると、一部の機能が使用不可能になる可能性があります。ご確認ください。', freeQuota: '無料のクォータ', }, - addApiKey: 'APIキーを追加', - invalidApiKey: '無効なAPIキー', + addApiKey: 'API キーを追加', + invalidApiKey: '無効な API キー', encrypted: { - front: 'APIキーは', + front: 'API キーは', back: ' の技術で暗号化されて保存されます。', }, freeQuota: { @@ -429,17 +429,17 @@ const translation = { providerManaged: 'プロバイダ管理', providerManagedDescription: 'モデルプロバイダによって提供される認証情報を使用します。', defaultConfig: 'デフォルトの設定', - apiKeyStatusNormal: 'APIキーの状態は正常', + apiKeyStatusNormal: 'API キーの状態は正常', apiKeyRateLimit: 'レート制限に到達しました。{{seconds}}秒後に再度利用可能です', addConfig: '設定を追加', editConfig: '設定を編集', - loadBalancingLeastKeyWarning: '負荷分散を利用するには、最低2つのキーを有効化する必要があります。', - loadBalancingInfo: 'デフォルトでは、負荷分散はラウンドロビン方式を採用しています。レート制限が発生した場合、1分間のクールダウン期間が適用されます。', + loadBalancingLeastKeyWarning: '負荷分散を利用するには、最低 2 つのキーを有効化する必要があります。', + loadBalancingInfo: 'デフォルトでは、負荷分散はラウンドロビン方式を採用しています。レート制限が発生した場合、1 分間のクールダウン期間が適用されます。', upgradeForLoadBalancing: '負荷分散を利用するには、プランのアップグレードが必要です。', emptyProviderTitle: 'モデルプロバイダーが設定されていません', discoverMore: 'もっと発見する', installProvider: 'モデルプロバイダーをインストールする', - configureTip: 'APIキーを設定するか、使用するモデルを追加してください', + configureTip: 'API キーを設定するか、使用するモデルを追加してください', toBeConfigured: '設定中', emptyProviderTip: '最初にモデルプロバイダーをインストールしてください。', }, @@ -449,7 +449,7 @@ const translation = { configure: '設定', notion: { title: 'Notion', - description: 'ナレッジデータソースとしてNotionを使用します。', + description: 'ナレッジデータソースとして Notion を使用します。', connectedWorkspace: '接続済みワークスペース', addWorkspace: 'ワークスペースの追加', connected: '接続済み', @@ -477,36 +477,36 @@ const translation = { }, plugin: { serpapi: { - apiKey: 'APIキー', - apiKeyPlaceholder: 'APIキーを入力してください', - keyFrom: 'SerpAPIアカウントページからSerpAPIキーを取得してください', + apiKey: 'API キー', + apiKeyPlaceholder: 'API キーを入力してください', + keyFrom: 'SerpAPI アカウントページから SerpAPI キーを取得してください', }, }, apiBasedExtension: { - title: 'API拡張機能は、Difyのアプリケーション全体での簡単な使用のための設定を簡素化し、集中的なAPI管理を提供します。', - link: '独自のAPI拡張機能を開発する方法について学ぶ。', + title: 'API 拡張機能は、Dify のアプリケーション全体での簡単な使用のための設定を簡素化し、集中的な API 管理を提供します。', + link: '独自の API 拡張機能を開発する方法について学ぶ。', linkUrl: 'https://docs.dify.ai/en/guides/extension/api-based-extension/README', - add: 'API拡張機能を追加', + add: 'API 拡張機能を追加', selector: { - title: 'API拡張機能', - placeholder: 'API拡張機能を選択してください', - manage: 'API拡張機能を管理', + title: 'API 拡張機能', + placeholder: 'API 拡張機能を選択してください', + manage: 'API 拡張機能を管理', }, modal: { - title: 'API拡張機能を追加', - editTitle: 'API拡張機能を編集', + title: 'API 拡張機能を追加', + editTitle: 'API 拡張機能を編集', name: { title: '名前', placeholder: '名前を入力してください', }, apiEndpoint: { - title: 'APIエンドポイント', - placeholder: 'APIエンドポイントを入力してください', + title: 'API エンドポイント', + placeholder: 'API エンドポイントを入力してください', }, apiKey: { - title: 'APIキー', - placeholder: 'APIキーを入力してください', - lengthError: 'APIキーの長さは5文字未満にできません', + title: 'API キー', + placeholder: 'API キーを入力してください', + lengthError: 'API キーの長さは 5 文字未満にできません', }, }, type: 'タイプ', @@ -520,7 +520,7 @@ const translation = { appMenus: { overview: '監視', promptEng: 'オーケストレート', - apiAccess: 'APIアクセス', + apiAccess: 'API アクセス', logAndAnn: 'ログ&アナウンス', logs: 'ログ', }, @@ -565,10 +565,10 @@ const translation = { citation: { title: '引用', linkToDataset: 'ナレッジへのリンク', - characters: '文字数:', - hitCount: '検索回数:', - vectorHash: 'ベクトルハッシュ:', - hitScore: '検索スコア:', + characters: '文字数:', + hitCount: '検索回数:', + vectorHash: 'ベクトルハッシュ:', + hitScore: '検索スコア:', }, inputPlaceholder: '{{botName}} と話す', thought: '思考', @@ -596,7 +596,7 @@ const translation = { modal: { title: '例', user: 'こんにちは', - assistant: 'こんにちは! 今日はどのようにお手伝いできますか?', + assistant: 'こんにちは!今日はどのようにお手伝いできますか?', edit: '会話の役割名を編集', }, }, @@ -650,7 +650,7 @@ const translation = { fileUploader: { uploadFromComputer: 'ローカルアップロード', pasteFileLink: 'ファイルリンクの貼り付け', - pasteFileLinkInputPlaceholder: 'URLを入力...', + pasteFileLinkInputPlaceholder: 'URL を入力...', uploadFromComputerLimit: 'アップロードファイルは{{size}}を超えてはなりません', uploadFromComputerUploadError: 'ファイルのアップロードに失敗しました。再度アップロードしてください。', uploadFromComputerReadError: 'ファイルの読み取りに失敗しました。もう一度やり直してください。', @@ -659,7 +659,7 @@ const translation = { }, license: { expiring_plural: '有効期限 {{count}} 日', - expiring: '1日で有効期限が切れます', + expiring: '1 日で有効期限が切れます', unlimited: '無制限', }, pagination: { @@ -668,7 +668,7 @@ const translation = { you: 'あなた', imageInput: { browse: 'ブラウズする', - supportedFormats: 'PNG、JPG、JPEG、WEBP、およびGIFをサポートしています。', + supportedFormats: 'PNG、JPG、JPEG、WEBP、および GIF をサポートしています。', dropImageHere: 'ここに画像をドロップするか、', }, } diff --git a/web/i18n/ja-JP/custom.ts b/web/i18n/ja-JP/custom.ts index d9750713c5..a7dcf4e7a8 100644 --- a/web/i18n/ja-JP/custom.ts +++ b/web/i18n/ja-JP/custom.ts @@ -7,14 +7,14 @@ const translation = { suffix: 'ブランドをカスタマイズしましょう。', }, webapp: { - title: 'WebAppブランドのカスタマイズ', - removeBrand: 'Powered by Difyを削除', - changeLogo: 'Powered byブランド画像を変更', - changeLogoTip: '最小サイズ40x40pxのSVGまたはPNG形式', + title: 'WebApp ブランドのカスタマイズ', + removeBrand: 'Powered by Dify を削除', + changeLogo: 'Powered by ブランド画像を変更', + changeLogoTip: '最小サイズ 40x40px の SVG または PNG 形式', }, app: { title: 'アプリヘッダーブランドのカスタマイズ', - changeLogoTip: '最小サイズ80x80pxのSVGまたはPNG形式', + changeLogoTip: '最小サイズ 80x80px の SVG または PNG 形式', }, upload: 'アップロード', uploading: 'アップロード中', diff --git a/web/i18n/ja-JP/dataset-creation.ts b/web/i18n/ja-JP/dataset-creation.ts index a3f573cab1..15bee57c0b 100644 --- a/web/i18n/ja-JP/dataset-creation.ts +++ b/web/i18n/ja-JP/dataset-creation.ts @@ -11,31 +11,31 @@ const translation = { unavailable: 'このナレッジベースは利用できません', }, firecrawl: { - configFirecrawl: '🔥Firecrawlの設定', - apiKeyPlaceholder: 'firecrawl.devからのAPIキー', - getApiKeyLinkText: 'firecrawl.devからAPIキーを取得する', + configFirecrawl: '🔥Firecrawl の設定', + apiKeyPlaceholder: 'firecrawl.dev からの API キー', + getApiKeyLinkText: 'firecrawl.dev から API キーを取得する', }, jinaReader: { - getApiKeyLinkText: '無料のAPIキーを jina.ai で取得', + getApiKeyLinkText: '無料の API キーを jina.ai で取得', apiKeyPlaceholder: 'jina.ai からの API キー', - configJinaReader: 'Jina Readerの設定', + configJinaReader: 'Jina Reader の設定', }, stepOne: { filePreview: 'ファイルプレビュー', pagePreview: 'ページプレビュー', dataSourceType: { file: 'テキストファイルからインポート', - notion: 'Notionから同期', + notion: 'Notion から同期', web: 'ウェブサイトから同期', }, uploader: { title: 'テキストファイルをアップロード', button: 'ファイルまたはフォルダをドラッグアンドドロップする', browse: '参照', - tip: '{{supportTypes}}をサポートしています。1つあたりの最大サイズは{{size}}MBです。', + tip: '{{supportTypes}}をサポートしています。1 つあたりの最大サイズは{{size}}MB です。', validation: { typeError: 'サポートされていないファイルタイプです', - size: 'ファイルサイズが大きすぎます。最大サイズは{{size}}MBです', + size: 'ファイルサイズが大きすぎます。最大サイズは{{size}}MB です', count: '複数のファイルはサポートされていません', filesNumber: 'バッチアップロードの制限({{filesNumber}}個)に達しました。', }, @@ -43,8 +43,8 @@ const translation = { change: '変更', failed: 'アップロードに失敗しました', }, - notionSyncTitle: 'Notionが接続されていません', - notionSyncTip: 'Notionと同期するには、まずNotionへの接続が必要です。', + notionSyncTitle: 'Notion が接続されていません', + notionSyncTip: 'Notion と同期するには、まず Notion への接続が必要です。', connect: '接続する', cancel: 'キャンセル', button: '次へ', @@ -55,49 +55,49 @@ const translation = { input: 'ナレッジベースの名称', placeholder: '入力してください', nameNotEmpty: '名前は空にできません', - nameLengthInvalid: '名前は1〜40文字である必要があります', + nameLengthInvalid: '名前は 1〜40 文字である必要があります', cancelButton: 'キャンセル', confirmButton: '作成', failed: '作成に失敗しました', }, website: { chooseProvider: 'プロバイダーを選択する', - fireCrawlNotConfigured: 'Firecrawlが設定されていません', + fireCrawlNotConfigured: 'Firecrawl が設定されていません', fireCrawlNotConfiguredDescription: 'Firecrawl を使用するには、Firecrawl の API キーを設定してください。', jinaReaderNotConfigured: 'Jina Reader が設定されていません', - jinaReaderNotConfiguredDescription: '無料のAPIキーを入力して、Jina Readerを設定します。', + jinaReaderNotConfiguredDescription: '無料の API キーを入力して、Jina Reader を設定します。', configure: '設定', configureFirecrawl: '配置 Firecrawl', configureJinaReader: '配置 Jina Reader', run: '実行', - firecrawlTitle: '🔥Firecrawlを使っでウエブコンテンツを抽出', - firecrawlDoc: 'Firecrawlドキュメント', + firecrawlTitle: '🔥Firecrawl を使っでウエブコンテンツを抽出', + firecrawlDoc: 'Firecrawl ドキュメント', firecrawlDocLink: 'https://docs.dify.ai/en/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website', - jinaReaderTitle: 'サイト全体をMarkdownに変換する', - jinaReaderDoc: 'Jina Readerの詳細', + jinaReaderTitle: 'サイト全体を Markdown に変換する', + jinaReaderDoc: 'Jina Reader の詳細', jinaReaderDocLink: 'https://jina.ai/reader', - useSitemap: 'sitemap(サイトマップ)を使用する', - useSitemapTooltip: 'サイトマップに沿ってサイトをクロールします。そうでない場合、Jina Readerはページの関連性に基づいて繰り返しクロールし、ページ数は少なくなりますが、高品質のページが得られます。', + useSitemap: 'sitemap(サイトマップ) を使用する', + useSitemapTooltip: 'サイトマップに沿ってサイトをクロールします。そうでない場合、Jina Reader はページの関連性に基づいて繰り返しクロールし、ページ数は少なくなりますが、高品質のページが得られます。', options: 'オプション', crawlSubPage: 'サブページをクロールする', limit: '制限', maxDepth: '最大深度', excludePaths: 'パスを除外する', includeOnlyPaths: 'パスのみを含める', - extractOnlyMainContent: 'メインコンテンツのみを抽出する(ヘッダー、ナビ、フッターなどは抽出しない)', - exceptionErrorTitle: 'Firecrawl ジョブの実行中に例外が発生しました:', + extractOnlyMainContent: 'メインコンテンツのみを抽出する (ヘッダー、ナビ、フッターなどは抽出しない)', + exceptionErrorTitle: 'Firecrawl ジョブの実行中に例外が発生しました:', unknownError: '不明なエラー', - totalPageScraped: 'スクレイピングされた総ページ数:', + totalPageScraped: 'スクレイピングされた総ページ数:', selectAll: 'すべて選択', resetAll: 'すべてリセット', scrapTimeInfo: '{{time}} 秒以内に合計 {{total}} ページをスクレイピングしました', preview: 'プレビュー', - maxDepthTooltip: '入力されたURLを基にしたクローリング作業での設定可能な最大深度について説明します。深度0は入力されたURL自体のページを対象としたスクレイピングを意味します。深度1では、元のURLの直下にあるページ(URLに続く最初の"/"以降の内容)もスクレイピングの対象になります。この深度は指定した数値まで増加させることができ、それに応じてスクレイピングの範囲も広がっていきます。', - waterCrawlNotConfiguredDescription: 'APIキーを使ってWatercrawlを設定します。', + maxDepthTooltip: '入力された URL を基にしたクローリング作業での設定可能な最大深度について説明します。深度 0 は入力された URL 自体のページを対象としたスクレイピングを意味します。深度 1 では、元の URL の直下にあるページ(URL に続く最初の"/"以降の内容)もスクレイピングの対象になります。この深度は指定した数値まで増加させることができ、それに応じてスクレイピングの範囲も広がっていきます。', + waterCrawlNotConfiguredDescription: 'API キーを使って Watercrawl を設定します。', configureWatercrawl: 'ウォータークローラーを設定する', watercrawlDoc: 'ウォータークローリングの文書', - watercrawlTitle: 'Watercrawlを使用してウェブコンテンツを抽出する', - waterCrawlNotConfigured: 'Watercrawlは設定されていません', + watercrawlTitle: 'Watercrawl を使用してウェブコンテンツを抽出する', + waterCrawlNotConfigured: 'Watercrawl は設定されていません', watercrawlDocLink: 'https://docs.dify.ai/ja/guides/knowledge-base/create-knowledge-and-upload-documents/import-content-data/sync-from-website', }, }, @@ -110,22 +110,22 @@ const translation = { general: '汎用', generalTip: '汎用テキスト分割モードです。検索とコンテキスト抽出に同じチャンクを使用します。', parentChild: '親子', - parentChildTip: '親子分割モード(階層分割モード)では、子チャンクを検索に、親チャンクをコンテキスト抽出に使用します。', + parentChildTip: '親子分割モード (階層分割モード) では、子チャンクを検索に、親チャンクをコンテキスト抽出に使用します。', parentChunkForContext: 'コンテキスト用親チャンク', childChunkForRetrieval: '検索用子チャンク', paragraph: '段落', paragraphTip: '区切り文字と最大チャンク長に基づいてテキストを段落に分割し、分割されたテキストを検索用の親チャンクとして使用します。', fullDoc: '全文', - fullDocTip: 'ドキュメント全体を親チャンクとして使用し、直接検索します。パフォーマンス上の理由から、10000トークンを超えるテキストは自動的に切り捨てられます。', + fullDocTip: 'ドキュメント全体を親チャンクとして使用し、直接検索します。パフォーマンス上の理由から、10000 トークンを超えるテキストは自動的に切り捨てられます。', separator: 'チャンク識別子', separatorPlaceholder: '例えば改行(\\\\n)や特殊なセパレータ(例:「***」)', maxLength: '最大チャンク長', overlap: 'チャンクのオーバーラップ', - overlapTip: 'チャンクのオーバーラップを設定することで、それらの間の意味的な関連性を維持し、検索効果を向上させることができます。最大チャンクサイズの10%〜25%を設定することをおすすめします。', + overlapTip: 'チャンクのオーバーラップを設定することで、それらの間の意味的な関連性を維持し、検索効果を向上させることができます。最大チャンクサイズの 10%〜25% を設定することをおすすめします。', overlapCheck: 'チャンクのオーバーラップは最大チャンク長を超えてはいけません', rules: 'テキストの前処理ルール', removeExtraSpaces: '連続するスペース、改行、タブを置換する', - removeUrlEmails: 'すべてのURLとメールアドレスを削除する', + removeUrlEmails: 'すべての URL とメールアドレスを削除する', removeStopwords: '「a」「an」「the」などのストップワードを削除する', preview: 'プレビュー', previewChunk: 'チャンクをプレビュー', @@ -134,15 +134,15 @@ const translation = { qualified: '高品質', highQualityTip: '高品質モードで埋め込みを終了したら、経済的モードに戻すことはできません。', recommend: '推奨', - qualifiedTip: '埋め込みモデルを呼び出してドキュメントを処理し、より正確な検索を行うと、LLMが高品質の回答を生成するのに役立ちます。', - warning: 'モデルプロバイダのAPIキーを設定してください。', + qualifiedTip: '埋め込みモデルを呼び出してドキュメントを処理し、より正確な検索を行うと、LLM が高品質の回答を生成するのに役立ちます。', + warning: 'モデルプロバイダの API キーを設定してください。', click: '設定に移動', economical: '経済的', - economicalTip: '検索時にチャンクあたり10個のキーワードを使用することで、精度は低下しますが、トークン消費を抑えられます。', + economicalTip: '検索時にチャンクあたり 10 個のキーワードを使用することで、精度は低下しますが、トークン消費を抑えられます。', QATitle: '質問と回答形式でセグメント化', QATip: 'このオプションを有効にすると、追加のトークンが消費されます', QALanguage: '使用言語', - useQALanguage: 'Q&A形式で分割', + useQALanguage: 'Q&A 形式で分割', estimateCost: '見積もり', estimateSegment: '推定チャンク数', segmentCount: 'チャンク', @@ -159,28 +159,28 @@ const translation = { save: '保存して処理', cancel: 'キャンセル', sideTipTitle: 'なぜチャンクと前処理が必要なのか', - sideTipP1: 'テキストデータを処理する際、チャンクとクリーニングは2つの重要な前処理ステップです。', + sideTipP1: 'テキストデータを処理する際、チャンクとクリーニングは 2 つの重要な前処理ステップです。', sideTipP2: 'セグメンテーションは長いテキストを段落に分割し、モデルがより理解しやすくします。これにより、モデルの結果の品質と関連性が向上します。', sideTipP3: 'クリーニングは不要な文字や書式を削除し、ナレッジベースをよりクリーンで解析しやすいものにします。', sideTipP4: '適切なチャンクとクリーニングはモデルのパフォーマンスを向上させ、より正確で価値のある結果を提供します。', previewTitle: 'プレビュー', previewTitleButton: 'プレビュー', - previewButton: 'Q&A形式に切り替える', + previewButton: 'Q&A 形式に切り替える', previewSwitchTipStart: '現在のチャンクプレビューはテキスト形式です。質問と回答形式のプレビューに切り替えると、', previewSwitchTipEnd: ' 追加のトークンが消費されます', characters: '文字', indexSettingTip: 'インデックス方法を変更するには、', retrievalSettingTip: '検索方法を変更するには、', datasetSettingLink: 'ナレッジベース設定', - separatorTip: '区切り文字は、テキストを区切るために使用される文字です。\\n\\n と \\n は、段落と行を区切るために一般的に使用される区切り記号です。カンマ (\\n\\n,\\n) と組み合わせると、最大チャンク長を超えると、段落は行で区切られます。自分で定義した特別な区切り文字を使用することもできます(例:***)。', + separatorTip: '区切り文字は、テキストを区切るために使用される文字です。\\n\\n と \\n は、段落と行を区切るために一般的に使用される区切り記号です。カンマ (\\n\\n,\\n) と組み合わせると、最大チャンク長を超えると、段落は行で区切られます。自分で定義した特別な区切り文字を使用することもできます (例:***)。', maxLengthCheck: 'チャンクの最大長は {{limit}} 未満にする必要があります', previewChunkTip: 'プレビューを読み込むには、左側の \'チャンクをプレビュー\' ボタンをクリックしてください', - previewChunkCount: '推定チャンク数: {{count}}', + previewChunkCount: '推定チャンク数:{{count}}', switch: '切り替え', - qaSwitchHighQualityTipTitle: 'Q&A形式には高品質なインデックスが必要です', - qaSwitchHighQualityTipContent: '現在、高品質なインデックス作成のみがQ&A形式の分割をサポートしています。高品質モードに切り替えますか?', + qaSwitchHighQualityTipTitle: 'Q&A 形式には高品質なインデックスが必要です', + qaSwitchHighQualityTipContent: '現在、高品質なインデックス作成のみが Q&A 形式の分割をサポートしています。高品質モードに切り替えますか?', notAvailableForParentChild: '親子インデックスでは利用できません', - notAvailableForQA: 'Q&Aインデックスでは利用できません', + notAvailableForQA: 'Q&A インデックスでは利用できません', parentChildDelimiterTip: '区切り文字とは、テキストを分割するために使用される文字です。\\n\\n は、元のドキュメントを大きな親チャンクに分割する際におすすめです。独自の区切り文字も使用できます。', parentChildChunkDelimiterTip: '区切り文字とは、テキストを分割するために使用される文字です。\\n は、親チャンクを小さな子チャンクに分割する際におすすめです。独自の区切り文字も使用できます。', }, @@ -195,7 +195,7 @@ const translation = { resume: '処理を再開', navTo: 'ドキュメントに移動', sideTipTitle: '次は何ですか', - sideTipContent: 'ドキュメントのインデックスが完了したら、ナレッジベースをアプリケーションのコンテキストとして統合することができます。プロンプトオーケストレーションページでコンテキスト設定を見つけることができます。また、独立したChatGPTインデックスプラグインとしてリリースすることもできます。', + sideTipContent: 'ドキュメントのインデックスが完了したら、ナレッジベースをアプリケーションのコンテキストとして統合することができます。プロンプトオーケストレーションページでコンテキスト設定を見つけることができます。また、独立した ChatGPT インデックスプラグインとしてリリースすることもできます。', modelTitle: '埋め込みを停止してもよろしいですか?', modelContent: '後で処理を再開する必要がある場合は、中断した場所から続行します。', modelButtonConfirm: '確認', @@ -203,13 +203,13 @@ const translation = { }, otherDataSource: { title: '他のデータソースと接続しますか?', - description: '現在、Difyのナレッジベースには利用できるデータソースが限られています。Difyのナレッジベースにデータソースを提供いただくことは、プラットフォームの柔軟性と能力を向上させる上で非常に有益です。貢献ガイドをご用意していますので、ぜひご協力ください。詳細については、以下のリンクをクリックしてください。', + description: '現在、Dify のナレッジベースには利用できるデータソースが限られています。Dify のナレッジベースにデータソースを提供いただくことは、プラットフォームの柔軟性と能力を向上させる上で非常に有益です。貢献ガイドをご用意していますので、ぜひご協力ください。詳細については、以下のリンクをクリックしてください。', learnMore: '詳細はこちら', }, watercrawl: { - getApiKeyLinkText: 'watercrawl.devからAPIキーを取得してください。', + getApiKeyLinkText: 'watercrawl.dev から API キーを取得してください。', configWatercrawl: 'ウォータークローラーを設定する', - apiKeyPlaceholder: 'watercrawl.devからのAPIキー', + apiKeyPlaceholder: 'watercrawl.dev からの API キー', }, } diff --git a/web/i18n/ja-JP/dataset-documents.ts b/web/i18n/ja-JP/dataset-documents.ts index 81047872ad..ecdbbf512c 100644 --- a/web/i18n/ja-JP/dataset-documents.ts +++ b/web/i18n/ja-JP/dataset-documents.ts @@ -1,11 +1,11 @@ const translation = { list: { title: 'ドキュメント', - desc: 'すべてのファイルがここに表示され、ナレッジベース全体がDifyの引用やチャットプラグインを介してリンクされるか、インデックス化されることができます。', + desc: 'すべてのファイルがここに表示され、ナレッジベース全体が Dify の引用やチャットプラグインを介してリンクされるか、インデックス化されることができます。', learnMore: '詳細はこちら', addFile: 'ファイルを追加', addPages: 'ページを追加', - addUrl: 'URLを追加', + addUrl: 'URL を追加', table: { header: { fileName: 'ファイル名', @@ -51,10 +51,10 @@ const translation = { empty: { title: 'まだドキュメントがありません', upload: { - tip: 'ファイルをアップロードしたり、ウェブサイトから同期したり、NotionやGitHubなどのWebアプリから同期することができます。', + tip: 'ファイルをアップロードしたり、ウェブサイトから同期したり、Notion や GitHub などの Web アプリから同期することができます。', }, sync: { - tip: 'Difyは定期的にNotionからファイルをダウンロードし、処理を完了します。', + tip: 'Dify は定期的に Notion からファイルをダウンロードし、処理を完了します。', }, }, delete: { @@ -63,9 +63,9 @@ const translation = { }, batchModal: { title: '一括追加', - csvUploadTitle: 'CSVファイルをここにドラッグアンドドロップするか、', + csvUploadTitle: 'CSV ファイルをここにドラッグアンドドロップするか、', browse: '参照', - tip: 'CSVファイルは次の構造に準拠する必要があります:', + tip: 'CSV ファイルは次の構造に準拠する必要があります:', question: '質問', answer: '回答', contentTitle: 'チャンクの内容', @@ -82,8 +82,8 @@ const translation = { }, metadata: { title: 'メタデータ', - desc: 'ドキュメントのメタデータにラベルを付けることで、AIがタイムリーにアクセスできるようになり、ユーザーに参照元が公開されます。', - dateTimeFormat: 'YYYY年M月D日 hh:mm A', + desc: 'ドキュメントのメタデータにラベルを付けることで、AI がタイムリーにアクセスできるようになり、ユーザーに参照元が公開されます。', + dateTimeFormat: 'YYYY 年 M 月 D 日 hh:mm A', docTypeSelectTitle: 'ドキュメントタイプを選択してください', docTypeChangeTitle: 'ドキュメントタイプを変更', docTypeSelectWarning: @@ -95,8 +95,8 @@ const translation = { }, source: { upload_file: 'ファイルをアップロード', - notion: 'Notionから同期', - github: 'GitHubから同期', + notion: 'Notion から同期', + github: 'GitHub から同期', }, type: { book: '書籍', @@ -105,10 +105,10 @@ const translation = { socialMediaPost: 'ソーシャルメディアの投稿', personalDocument: '個人のドキュメント', businessDocument: 'ビジネスドキュメント', - IMChat: 'IMチャット', - wikipediaEntry: 'Wikipediaのエントリー', - notion: 'Notionから同期', - github: 'GitHubから同期', + IMChat: 'IM チャット', + wikipediaEntry: 'Wikipedia のエントリー', + notion: 'Notion から同期', + github: 'GitHub から同期', technicalParameters: '技術的なパラメータ', }, field: { @@ -151,7 +151,7 @@ const translation = { platform: 'プラットフォーム', authorUsername: '著者/ユーザー名', publishDate: '公開日', - postURL: '投稿URL', + postURL: '投稿 URL', topicsTags: 'トピック/タグ', }, personalDocument: { @@ -182,7 +182,7 @@ const translation = { wikipediaEntry: { title: 'タイトル', language: '言語', - webpageURL: 'ウェブページURL', + webpageURL: 'ウェブページ URL', editorContributor: '編集者/寄稿者', lastEditDate: '最終編集日', summaryIntroduction: '概要/紹介', @@ -355,11 +355,11 @@ const translation = { newChildChunk: '新しい子チャンク', keywords: 'キーワード', addKeyWord: 'キーワードを追加', - keywordError: 'キーワードの最大長は20です', + keywordError: 'キーワードの最大長は 20 です', characters_one: '文字', characters_other: '文字', hitCount: '検索回数', - vectorHash: 'ベクトルハッシュ: ', + vectorHash: 'ベクトルハッシュ:', questionPlaceholder: 'ここに質問を追加', questionEmpty: '質問は空にできません', answerPlaceholder: 'ここに回答を追加', @@ -367,7 +367,7 @@ const translation = { contentPlaceholder: 'ここに内容を追加', contentEmpty: '内容は空にできません', newTextSegment: '新しいテキストチャンク', - newQaSegment: '新しいQ&Aチャンク', + newQaSegment: '新しい Q&A チャンク', addChunk: 'チャンクを追加', addChildChunk: '子チャンクを追加', addAnother: '続けて追加', diff --git a/web/i18n/ja-JP/dataset-hit-testing.ts b/web/i18n/ja-JP/dataset-hit-testing.ts index 7b00455636..9e6f5e6c05 100644 --- a/web/i18n/ja-JP/dataset-hit-testing.ts +++ b/web/i18n/ja-JP/dataset-hit-testing.ts @@ -13,7 +13,7 @@ const translation = { input: { title: 'ソーステキスト', placeholder: 'テキストを入力してください。短い記述文がおすすめです。', - countWarning: '最大200文字まで入力できます。', + countWarning: '最大 200 文字まで入力できます。', indexWarning: '高品質のナレッジのみ。', testing: 'テスト中', }, diff --git a/web/i18n/ja-JP/dataset-settings.ts b/web/i18n/ja-JP/dataset-settings.ts index b0fd2ec55b..87a48dd005 100644 --- a/web/i18n/ja-JP/dataset-settings.ts +++ b/web/i18n/ja-JP/dataset-settings.ts @@ -7,7 +7,7 @@ const translation = { nameError: '名前は空にできません', desc: 'ナレッジベースの説明', descInfo: 'ナレッジベースの内容を概説するための明確なテキストの説明を書いてください。この説明は、複数のナレッジから推論を選択する際の基準として使用されます。', - descPlaceholder: 'このデータセットの内容を記述してください。詳細に記述することで、AIがデータセットの内容に迅速にアクセスできるようになります。空欄の場合、LangGeniusはデフォルトの検索方法を使用します。', + descPlaceholder: 'このデータセットの内容を記述してください。詳細に記述することで、AI がデータセットの内容に迅速にアクセスできるようになります。空欄の場合、LangGenius はデフォルトの検索方法を使用します。', helpText: '適切なデータセットの説明を作成する方法を学びましょう。', descWrite: '良いナレッジベースの説明の書き方を学ぶ。', permissions: '権限', @@ -17,10 +17,10 @@ const translation = { me: '(あなた)', indexMethod: 'インデックス方法', indexMethodHighQuality: '高品質', - indexMethodHighQualityTip: 'より正確な検索のため、埋め込みモデルを呼び出してドキュメントを処理することで、LLMは高品質な回答を生成できます。', + indexMethodHighQualityTip: 'より正確な検索のため、埋め込みモデルを呼び出してドキュメントを処理することで、LLM は高品質な回答を生成できます。', upgradeHighQualityTip: '高品質モードにアップグレードすると、経済的モードには戻せません。', indexMethodEconomy: '経済的', - indexMethodEconomyTip: 'チャンクあたり10個のキーワードを検索に使用します。トークンは消費しませんが、検索精度は低下します。', + indexMethodEconomyTip: 'チャンクあたり 10 個のキーワードを検索に使用します。トークンは消費しませんが、検索精度は低下します。', embeddingModel: '埋め込みモデル', embeddingModelTip: '埋め込みモデルを変更するには、', embeddingModelTipLink: '設定', @@ -32,10 +32,10 @@ const translation = { longDescription: ' 検索方法についての詳細については、いつでもナレッジベースの設定で変更できます。', }, save: '保存', - externalKnowledgeID: '外部ナレッジベースID', + externalKnowledgeID: '外部ナレッジベース ID', retrievalSettings: '取得設定', - externalKnowledgeAPI: '外部ナレッジベースAPI', - indexMethodChangeToEconomyDisabledTip: 'HQからECOへのダウングレードはできません。', + externalKnowledgeAPI: '外部ナレッジベース API', + indexMethodChangeToEconomyDisabledTip: 'HQ から ECO へのダウングレードはできません。', searchModel: 'モデル検索', }, } diff --git a/web/i18n/ja-JP/dataset.ts b/web/i18n/ja-JP/dataset.ts index 1078fee69d..2bdc4a8d28 100644 --- a/web/i18n/ja-JP/dataset.ts +++ b/web/i18n/ja-JP/dataset.ts @@ -9,33 +9,33 @@ const translation = { fullDoc: '全体', }, externalTag: '外部', - externalAPI: '外部API', - externalAPIPanelTitle: '外部ナレッジベース連携API', - externalKnowledgeId: '外部ナレッジベースID', + externalAPI: '外部 API', + externalAPIPanelTitle: '外部ナレッジベース連携 API', + externalKnowledgeId: '外部ナレッジベース ID', externalKnowledgeName: '外部ナレッジベース名', externalKnowledgeDescription: 'ナレッジベースの説明', - externalKnowledgeIdPlaceholder: 'ナレッジベースIDを入力', + externalKnowledgeIdPlaceholder: 'ナレッジベース ID を入力', externalKnowledgeNamePlaceholder: 'ナレッジベース名を入力', externalKnowledgeDescriptionPlaceholder: 'このナレッジベースの説明(任意)', learnHowToWriteGoodKnowledgeDescription: '効果的なナレッジベースの説明の書き方', - externalAPIPanelDescription: '外部ナレッジベース連携APIは、Dify外のナレッジベースと連携し、そこからナレッジベースを取得するために使用します。', - externalAPIPanelDocumentation: '外部ナレッジベース連携APIの作成方法', + externalAPIPanelDescription: '外部ナレッジベース連携 API は、Dify 外のナレッジベースと連携し、そこからナレッジベースを取得するために使用します。', + externalAPIPanelDocumentation: '外部ナレッジベース連携 API の作成方法', localDocs: 'ローカルドキュメント', documentCount: ' ドキュメント', wordCount: ' k 単語', appCount: ' リンクされたアプリ', createDataset: 'ナレッジベースを作成', - createNewExternalAPI: '新しい外部ナレッジベース連携APIを作成', - noExternalKnowledge: '外部ナレッジベース連携APIがありません。ここをクリックして作成してください', - createExternalAPI: '外部ナレッジベース連携APIを追加', - editExternalAPIFormTitle: '外部ナレッジベース連携APIを編集', + createNewExternalAPI: '新しい外部ナレッジベース連携 API を作成', + noExternalKnowledge: '外部ナレッジベース連携 API がありません。ここをクリックして作成してください', + createExternalAPI: '外部ナレッジベース連携 API を追加', + editExternalAPIFormTitle: '外部ナレッジベース連携 API を編集', editExternalAPITooltipTitle: '連携中のナレッジベース', editExternalAPIConfirmWarningContent: { - front: 'この外部ナレッジベース連携APIは', + front: 'この外部ナレッジベース連携 API は', end: '件の外部ナレッジベースと連携しており、この変更はすべてに適用されます。変更を保存しますか?', }, editExternalAPIFormWarning: { - front: 'この外部APIは', + front: 'この外部 API は', end: '件の外部ナレッジベースと連携しています', }, deleteExternalAPIConfirmWarningContent: { @@ -44,32 +44,32 @@ const translation = { end: 'しますか?', }, content: { - front: 'この外部ナレッジベース連携APIは', - end: '件の外部ナレッジベースと連携しています。このAPIを削除すると、すべて無効になります。このAPIを削除しますか?', + front: 'この外部ナレッジベース連携 API は', + end: '件の外部ナレッジベースと連携しています。この API を削除すると、すべて無効になります。この API を削除しますか?', }, - noConnectionContent: 'このAPIを削除しますか?', + noConnectionContent: 'この API を削除しますか?', }, selectExternalKnowledgeAPI: { - placeholder: '外部ナレッジベース連携APIを選択', + placeholder: '外部ナレッジベース連携 API を選択', }, connectDataset: '外部ナレッジベースと連携', connectDatasetIntro: { title: '外部ナレッジベースとの連携方法', content: { - front: '外部ナレッジベースと連携するには、まず外部APIを作成する必要があります。以下の手順を参照し、', - link: '外部APIの作成方法', - end: 'をご確認ください。次に、対応するナレッジベースIDを左側のフォームに入力してください。すべての情報が正しければ、連携ボタンをクリックすると、自動的にナレッジベースの検索テストに移動します。', + front: '外部ナレッジベースと連携するには、まず外部 API を作成する必要があります。以下の手順を参照し、', + link: '外部 API の作成方法', + end: 'をご確認ください。次に、対応するナレッジベース ID を左側のフォームに入力してください。すべての情報が正しければ、連携ボタンをクリックすると、自動的にナレッジベースの検索テストに移動します。', }, learnMore: '詳細はこちら', }, connectHelper: { - helper1: 'APIとナレッジベースIDを使って外部ナレッジベースと連携します。現在、', + helper1: 'API とナレッジベース ID を使って外部ナレッジベースと連携します。現在、', helper2: '検索機能のみがサポートされています。', helper3: 'この機能を使用する前に、', helper4: 'ヘルプドキュメント', helper5: 'をよくお読みください。', }, - createDatasetIntro: '独自のテキストデータをインポートするか、LLMコンテキストの強化のためにWebhookを介してリアルタイムでデータを書き込むことができます。', + createDatasetIntro: '独自のテキストデータをインポートするか、LLM コンテキストの強化のために Webhook を介してリアルタイムでデータを書き込むことができます。', deleteDatasetConfirmTitle: 'このナレッジベースを削除しますか?', deleteDatasetConfirmContent: 'ナレッジベースを削除すると元に戻すことはできません。ユーザーはもはやあなたのナレッジベースにアクセスできず、すべてのプロンプトの設定とログが永久に削除されます。', @@ -77,12 +77,12 @@ const translation = { datasetDeleted: 'ナレッジベースが削除されました', datasetDeleteFailed: 'ナレッジベースの削除に失敗しました', didYouKnow: 'ご存知ですか?', - intro1: 'ナレッジベースはDifyアプリケーションに統合することができます', + intro1: 'ナレッジベースは Dify アプリケーションに統合することができます', intro2: 'コンテキストとして', intro3: '、', intro4: 'または', intro5: '作成することができます', - intro6: '単体のChatGPTインデックスプラグインとして公開するために', + intro6: '単体の ChatGPT インデックスプラグインとして公開するために', unavailable: '利用不可', unavailableTip: '埋め込みモデルが利用できません。デフォルトの埋め込みモデルを設定する必要があります', datasets: 'ナレッジベース', @@ -93,13 +93,13 @@ const translation = { }, externalAPIForm: { name: '名前', - endpoint: 'APIエンドポイント', - apiKey: 'APIキー', + endpoint: 'API エンドポイント', + apiKey: 'API キー', save: '保存', cancel: 'キャンセル', edit: '編集', encrypted: { - front: 'APIトークンは', + front: 'API トークンは', end: '技術で暗号化され、安全に保存されます。', }, }, @@ -114,19 +114,19 @@ const translation = { }, hybrid_search: { title: 'ハイブリッド検索', - description: '全文検索とベクトル検索を同時に実行し、ユーザーのクエリに最適なマッチを選択するためにRerank付けを行います。RerankモデルAPIの設定が必要です。', + description: '全文検索とベクトル検索を同時に実行し、ユーザーのクエリに最適なマッチを選択するために Rerank 付けを行います。Rerank モデル API の設定が必要です。', recommend: '推奨', }, invertedIndex: { title: '転置インデックス', - description: '効率的な検索に使用される構造です。各用語が含まれるドキュメントまたはWebページを指すように、用語ごとに整理されています。', + description: '効率的な検索に使用される構造です。各用語が含まれるドキュメントまたは Web ページを指すように、用語ごとに整理されています。', }, change: '変更', changeRetrievalMethod: '検索方法の変更', }, docsFailedNotice: 'ドキュメントのインデックス作成に失敗しました', retry: '再試行', - documentsDisabled: '{{num}}件のドキュメントが無効 - 30日以上非アクティブ', + documentsDisabled: '{{num}}件のドキュメントが無効 - 30 日以上非アクティブ', enable: '有効化', indexingTechnique: { high_quality: '高品質', @@ -139,12 +139,12 @@ const translation = { invertedIndex: '転置', }, defaultRetrievalTip: 'デフォルトでは、マルチパス検索が使用されます。複数のナレッジベースから情報を取得した後、再ランキングを行います。', - mixtureHighQualityAndEconomicTip: '高品質なナレッジベースとコスト重視のナレッジベースを混在させるには、Rerankモデルが必要です。', - inconsistentEmbeddingModelTip: '選択されたナレッジベースの埋め込みモデルに一貫性がない場合、Rerankモデルが必要です。', - mixtureInternalAndExternalTip: '内部と外部のナレッジベースを混在させる場合、Rerankモデルが必要です。', - allExternalTip: '外部ナレッジベースのみを使用する場合、Rerankモデルを有効にするかを選択できます。有効にしない場合、検索結果はスコアに基づいてソートされます。異なるナレッジベースで検索戦略が一貫していないと、結果が不正確になる可能性があります。', + mixtureHighQualityAndEconomicTip: '高品質なナレッジベースとコスト重視のナレッジベースを混在させるには、Rerank モデルが必要です。', + inconsistentEmbeddingModelTip: '選択されたナレッジベースの埋め込みモデルに一貫性がない場合、Rerank モデルが必要です。', + mixtureInternalAndExternalTip: '内部と外部のナレッジベースを混在させる場合、Rerank モデルが必要です。', + allExternalTip: '外部ナレッジベースのみを使用する場合、Rerank モデルを有効にするかを選択できます。有効にしない場合、検索結果はスコアに基づいてソートされます。異なるナレッジベースで検索戦略が一貫していないと、結果が不正確になる可能性があります。', retrievalSettings: '検索設定', - rerankSettings: 'Rerank設定', + rerankSettings: 'Rerank 設定', weightedScore: { title: 'ウェイト設定', description: '重みを調整することで、並べ替え戦略はセマンティックマッチングとキーワードマッチングのどちらを優先するかを決定します。', @@ -154,9 +154,9 @@ const translation = { semantic: 'セマンティクス', keyword: 'キーワード', }, - nTo1RetrievalLegacy: '製品計画によると、N-to-1 Retrievalは9月に正式に廃止される予定です。それまでは通常通り使用できます。', + nTo1RetrievalLegacy: '製品計画によると、N-to-1 Retrieval は 9 月に正式に廃止される予定です。それまでは通常通り使用できます。', nTo1RetrievalLegacyLink: '詳細はこちら', - nTo1RetrievalLegacyLinkText: ' N-to-1 retrievalは9月に正式に廃止されます。', + nTo1RetrievalLegacyLinkText: ' N-to-1 retrieval は 9 月に正式に廃止されます。', batchAction: { selected: '選択済み', enable: '有効にする', @@ -168,7 +168,7 @@ const translation = { preprocessDocument: '{{num}}件のドキュメントを前処理', allKnowledge: 'ナレッジベース全体', allKnowledgeDescription: 'このワークスペースにナレッジベース全体を表示する場合に選択します。ワークスペースのオーナーのみがすべてのナレッジベースを管理できます。', - embeddingModelNotAvailable: 'Embeddingモデル不可用。', + embeddingModelNotAvailable: 'Embedding モデル不可用。', metadata: { metadata: 'メタデータ', addMetadata: 'メタデータを追加', diff --git a/web/i18n/ja-JP/education.ts b/web/i18n/ja-JP/education.ts index d51bac817d..4fae5ac28e 100644 --- a/web/i18n/ja-JP/education.ts +++ b/web/i18n/ja-JP/education.ts @@ -1,7 +1,7 @@ const translation = { toVerified: '教育認証を取得', toVerifiedTip: { - front: '現在、教育認証ステータスを取得する資格があります。以下に教育情報を入力し、認証プロセスを完了すると、Difyプロフェッショナルプランの', + front: '現在、教育認証ステータスを取得する資格があります。以下に教育情報を入力し、認証プロセスを完了すると、Dify プロフェッショナルプランの', coupon: '50%割引クーポン', end: 'を受け取ることができます。', }, @@ -29,18 +29,18 @@ const translation = { privacyPolicy: 'プライバシーポリシー', }, option: { - age: '18歳以上であることを確認します。', - inSchool: '提供した教育機関に在籍または勤務している ことを確認します。Difyは在籍/雇用証明の提出を求める場合があります。不正な情報を申告した場合、教育認証に基づき免除された費用を支払うことに同意します。', + age: '18 歳以上であることを確認します。', + inSchool: '提供した教育機関に在籍または勤務している ことを確認します。Dify は在籍/雇用証明の提出を求める場合があります。不正な情報を申告した場合、教育認証に基づき免除された費用を支払うことに同意します。', }, }, }, submit: '送信', submitError: 'フォームの送信に失敗しました。しばらくしてから再度ご提出ください。', learn: '教育認証の取得方法はこちら', - successTitle: 'Dify教育認証を取得しました!', - successContent: 'お客様のアカウントに Difyプロフェッショナルプランの50%割引クーポン を発行しました。有効期間は 1年間 ですので、期限内にご利用ください。', - rejectTitle: 'Dify教育認証が拒否されました', - rejectContent: '申し訳ございませんが、このメールアドレスでは 教育認証 の資格を取得できず、Difyプロフェッショナルプランの50%割引クーポン を受け取ることはできません。', + successTitle: 'Dify 教育認証を取得しました!', + successContent: 'お客様のアカウントに Dify プロフェッショナルプランの 50% 割引クーポン を発行しました。有効期間は 1 年間 ですので、期限内にご利用ください。', + rejectTitle: 'Dify 教育認証が拒否されました', + rejectContent: '申し訳ございませんが、このメールアドレスでは 教育認証 の資格を取得できず、Dify プロフェッショナルプランの 50%割引クーポン を受け取ることはできません。', emailLabel: '現在のメールアドレス', } diff --git a/web/i18n/ja-JP/login.ts b/web/i18n/ja-JP/login.ts index 3db651c580..84ab9eecd0 100644 --- a/web/i18n/ja-JP/login.ts +++ b/web/i18n/ja-JP/login.ts @@ -1,6 +1,6 @@ const translation = { pageTitle: 'はじめましょう!👋', - welcome: 'Difyへようこそ。続行するにはログインしてください。', + welcome: 'Dify へようこそ。続行するにはログインしてください。', email: 'メールアドレス', emailPlaceholder: 'メールアドレスを入力してください', password: 'パスワード', @@ -9,10 +9,10 @@ const translation = { namePlaceholder: 'ユーザー名を入力してください', forget: 'パスワードをお忘れですか?', signBtn: 'サインイン', - sso: 'SSOに続ける', + sso: 'SSO に続ける', installBtn: 'セットアップ', setAdminAccount: '管理者アカウントの設定', - setAdminAccountDesc: 'アプリケーションの作成やLLMプロバイダの管理など、管理者アカウントの最大権限を設定します。', + setAdminAccountDesc: 'アプリケーションの作成や LLM プロバイダの管理など、管理者アカウントの最大権限を設定します。', createAndSignIn: '作成してサインイン', oneMoreStep: 'あと一歩', createSample: 'この情報を基に、サンプルアプリケーションを作成します', @@ -20,14 +20,14 @@ const translation = { invitationCodePlaceholder: '招待コードを入力してください', interfaceLanguage: 'インターフェース言語', timezone: 'タイムゾーン', - go: 'Difyへ移動', + go: 'Dify へ移動', sendUsMail: '自己紹介をメールで送信し、招待リクエストを処理します。', acceptPP: 'プライバシーポリシーを読み、同意します', reset: 'パスワードをリセットするには、次のコマンドを実行してください', - withGitHub: 'GitHubで続行', - withGoogle: 'Googleで続行', - rightTitle: 'LLMのフルポテンシャルを解き放つ', - rightDesc: '魅力的で操作可能で改善可能なAIアプリケーションを簡単に構築します。', + withGitHub: 'GitHub で続行', + withGoogle: 'Google で続行', + rightTitle: 'LLM のフルポテンシャルを解き放つ', + rightDesc: '魅力的で操作可能で改善可能な AI アプリケーションを簡単に構築します。', tos: '利用規約', pp: 'プライバシーポリシー', tosDesc: 'サインアップすることで、以下に同意するものとします', @@ -53,19 +53,19 @@ const translation = { emailInValid: '有効なメールアドレスを入力してください', nameEmpty: '名前は必須です', passwordEmpty: 'パスワードは必須です', - passwordLengthInValid: 'パスワードは8文字以上でなければなりません', - passwordInvalid: 'パスワードは文字と数字を含み、長さは8以上である必要があります', + passwordLengthInValid: 'パスワードは 8 文字以上でなければなりません', + passwordInvalid: 'パスワードは文字と数字を含み、長さは 8 以上である必要があります', registrationNotAllowed: 'アカウントが見つかりません。登録するためにシステム管理者に連絡してください。', }, license: { - tip: 'GitHubのオープンソースライセンスを確認してから、Dify Community Editionを開始してください。', + tip: 'GitHub のオープンソースライセンスを確認してから、Dify Community Edition を開始してください。', link: 'オープンソースライセンス', }, join: '参加する', joinTipStart: 'あなたを招待します', joinTipEnd: 'チームに参加する', invalid: 'リンクの有効期限が切れています', - explore: 'Difyを探索する', + explore: 'Dify を探索する', activatedTipStart: 'あなたは', activatedTipEnd: 'チームに参加しました', activated: '今すぐサインイン', @@ -74,13 +74,13 @@ const translation = { checkCode: { invalidCode: '無効なコード', verify: '確かめる', - verificationCodePlaceholder: '6桁のコードを入力してください', + verificationCodePlaceholder: '6 桁のコードを入力してください', useAnotherMethod: '別の方法を使用する', - didNotReceiveCode: 'コードが届きませんか?', + didNotReceiveCode: 'コードが届きませんか?', resend: '再送', verificationCode: '認証コード', tips: '確認コードを{{email}}に送信します。', - validTime: 'コードは5分間有効であることに注意してください', + validTime: 'コードは 5 分間有効であることに注意してください', emptyCode: 'コードが必要です', checkYourEmail: 'メールをチェックしてください', }, @@ -90,7 +90,7 @@ const translation = { resetPassword: 'パスワードのリセット', changePasswordBtn: 'パスワードを設定する', setYourAccount: 'アカウントを設定する', - withSSO: 'SSOを続行する', + withSSO: 'SSO を続行する', noLoginMethod: '認証方法が構成されていません', backToLogin: 'ログインに戻る', continueWithCode: 'コードで続行', @@ -98,17 +98,17 @@ const translation = { usePassword: 'パスワードを使用', sendVerificationCode: '確認コードの送信', enterYourName: 'ユーザー名を入力してください', - resetPasswordDesc: 'Difyへのサインアップに使用したメールアドレスを入力すると、パスワードリセットメールが送信されます。', + resetPasswordDesc: 'Dify へのサインアップに使用したメールアドレスを入力すると、パスワードリセットメールが送信されます。', licenseLost: 'ライセンスを失った', - licenseExpiredTip: 'ワークスペースの Dify Enterprise ライセンスの有効期限が切れています。Difyを引き続き使用するには、管理者に連絡してください。', + licenseExpiredTip: 'ワークスペースの Dify Enterprise ライセンスの有効期限が切れています。Dify を引き続き使用するには、管理者に連絡してください。', licenseInactive: 'ライセンスが非アクティブです', - licenseInactiveTip: 'ワークスペースの Dify Enterprise ライセンスが非アクティブです。Difyを引き続き使用するには、管理者に連絡してください。', + licenseInactiveTip: 'ワークスペースの Dify Enterprise ライセンスが非アクティブです。Dify を引き続き使用するには、管理者に連絡してください。', licenseExpired: 'ライセンスの有効期限が切れています', - licenseLostTip: 'Difyライセンスサーバーへの接続に失敗しました。続けてDifyを使用するために管理者に連絡してください。', + licenseLostTip: 'Dify ライセンスサーバーへの接続に失敗しました。続けて Dify を使用するために管理者に連絡してください。', webapp: { - noLoginMethod: 'Webアプリに対して認証方法が構成されていません', + noLoginMethod: 'Web アプリに対して認証方法が構成されていません', noLoginMethodTip: 'システム管理者に連絡して、認証方法を追加してください。', - disabled: 'Webアプリの認証が無効になっています。システム管理者に連絡して有効にしてください。直接アプリを使用してみてください。', + disabled: 'Web アプリの認証が無効になっています。システム管理者に連絡して有効にしてください。直接アプリを使用してみてください。', }, } diff --git a/web/i18n/ja-JP/plugin.ts b/web/i18n/ja-JP/plugin.ts index dfb4efe679..bc976074ea 100644 --- a/web/i18n/ja-JP/plugin.ts +++ b/web/i18n/ja-JP/plugin.ts @@ -17,7 +17,7 @@ const translation = { list: { source: { local: 'ローカルパッケージファイルからインストール', - github: 'GitHubからインストールする', + github: 'GitHub からインストールする', marketplace: 'マーケットプレイスからインストール', }, noInstalled: 'プラグインはインストールされていません', @@ -33,7 +33,7 @@ const translation = { marketplace: 'マーケットプレイスからインストールされました', local: 'ローカルプラグイン', debugging: 'デバッグプラグイン', - github: 'Githubからインストールしました', + github: 'Github からインストールしました', }, operation: { info: 'プラグイン情報', @@ -51,7 +51,7 @@ const translation = { unsupportedContent2: 'バージョンを切り替えるにはクリックしてください。', unsupportedContent: 'インストールされたプラグインのバージョンは、このアクションを提供していません。', title: 'ツールを追加', - uninstalledContent: 'このプラグインはローカル/GitHubリポジトリからインストールされます。インストール後にご利用ください。', + uninstalledContent: 'このプラグインはローカル/GitHub リポジトリからインストールされます。インストール後にご利用ください。', descriptionLabel: 'ツールの説明', auto: '自動', params: '推論設定', @@ -59,13 +59,13 @@ const translation = { placeholder: 'ツールを選択...', uninstalledTitle: 'ツールがインストールされていません', empty: 'ツールを追加するには「+」ボタンをクリックしてください。複数のツールを追加できます。', - paramsTip1: 'LLM推論パラメータを制御します。', + paramsTip1: 'LLM 推論パラメータを制御します。', toolLabel: '道具', unsupportedTitle: 'サポートされていないアクション', toolSetting: 'ツール設定', }, endpointDisableTip: 'エンドポイントを無効にする', - endpointModalDesc: '設定が完了すると、APIエンドポイントを介してプラグインが提供する機能を使用できます。', + endpointModalDesc: '設定が完了すると、API エンドポイントを介してプラグインが提供する機能を使用できます。', endpointDisableContent: '{{name}}を無効にしますか?', endpointModalTitle: 'エンドポイントを設定する', endpointDeleteTip: 'エンドポイントを削除', @@ -141,15 +141,15 @@ const translation = { installFromGitHub: { installedSuccessfully: 'インストールに成功しました', installNote: '信頼できるソースからのみプラグインをインストールするようにしてください。', - updatePlugin: 'GitHubからプラグインを更新する', + updatePlugin: 'GitHub からプラグインを更新する', selectPackage: 'パッケージを選択', installFailed: 'インストールに失敗しました', selectPackagePlaceholder: 'パッケージを選択してください', - gitHubRepo: 'GitHubリポジトリ', + gitHubRepo: 'GitHub リポジトリ', selectVersionPlaceholder: 'バージョンを選択してください', uploadFailed: 'アップロードに失敗しました', selectVersion: 'バージョンを選択', - installPlugin: 'GitHubからプラグインをインストールする', + installPlugin: 'GitHub からプラグインをインストールする', }, upgrade: { title: 'プラグインをインストールする', @@ -162,14 +162,14 @@ const translation = { }, error: { fetchReleasesError: 'リリースを取得できません。後でもう一度お試しください。', - inValidGitHubUrl: '無効なGitHub URLです。有効なURLを次の形式で入力してください: https://github.com/owner/repo', - noReleasesFound: 'リリースは見つかりません。GitHubリポジトリまたは入力URLを確認してください。', + inValidGitHubUrl: '無効な GitHub URL です。有効な URL を次の形式で入力してください:https://github.com/owner/repo', + noReleasesFound: 'リリースは見つかりません。GitHub リポジトリまたは入力 URL を確認してください。', }, marketplace: { - empower: 'AI開発をサポートする', + empower: 'AI 開発をサポートする', discover: '探索', and: 'と', - difyMarketplace: 'Difyマーケットプレイス', + difyMarketplace: 'Dify マーケットプレイス', moreFrom: 'マーケットプレイスからのさらなる情報', noPluginFound: 'プラグインが見つかりません', pluginsResult: '{{num}} 件の結果', @@ -181,8 +181,8 @@ const translation = { firstReleased: 'リリース順', }, viewMore: 'もっと見る', - verifiedTip: 'このプラグインはDifyによって認証されています', - partnerTip: 'このプラグインはDifyのパートナーによって認証されています', + verifiedTip: 'このプラグインは Dify によって認証されています', + partnerTip: 'このプラグインは Dify のパートナーによって認証されています', }, task: { installError: '{{errorLength}} プラグインのインストールに失敗しました。表示するにはクリックしてください。', @@ -190,7 +190,7 @@ const translation = { clearAll: 'すべてクリア', installedError: '{{errorLength}} プラグインのインストールに失敗しました', installingWithError: '{{installingLength}}個のプラグインをインストール中、{{successLength}}件成功、{{errorLength}}件失敗', - installing: '{{installingLength}}個のプラグインをインストール中、0個完了。', + installing: '{{installingLength}}個のプラグインをインストール中、0 個完了。', }, from: 'インストール元', install: '{{num}} インストール', @@ -207,7 +207,7 @@ const translation = { installPlugin: 'プラグインをインストールする', searchInMarketplace: 'マーケットプレイスで検索', submitPlugin: 'プラグインを提出する', - difyVersionNotCompatible: '現在のDifyバージョンはこのプラグインと互換性がありません。最小バージョンは{{minimalDifyVersion}}です。', + difyVersionNotCompatible: '現在の Dify バージョンはこのプラグインと互換性がありません。最小バージョンは{{minimalDifyVersion}}です。', metadata: { title: 'プラグイン', }, diff --git a/web/i18n/ja-JP/run-log.ts b/web/i18n/ja-JP/run-log.ts index 758e37c7de..2c4bc46331 100644 --- a/web/i18n/ja-JP/run-log.ts +++ b/web/i18n/ja-JP/run-log.ts @@ -19,7 +19,7 @@ const translation = { steps: '処理ステップ数', }, resultEmpty: { - title: '今回の実行ではJSON形式のみが出力されました', + title: '今回の実行では JSON 形式のみが出力されました', tipLeft: '詳細を確認するには', link: '詳細情報パネル', tipRight: 'へ移動してください', diff --git a/web/i18n/ja-JP/share-app.ts b/web/i18n/ja-JP/share-app.ts index 9db8926394..9e76f6518a 100644 --- a/web/i18n/ja-JP/share-app.ts +++ b/web/i18n/ja-JP/share-app.ts @@ -35,7 +35,7 @@ const translation = { }, generation: { tabs: { - create: '1回実行', + create: '1 回実行', batch: '一括実行', saved: '保存済み', }, @@ -44,7 +44,7 @@ const translation = { description: 'コンテンツ生成後に結果がここに表示されます', startCreateContent: '生成を開始', }, - title: 'AI文章作成', + title: 'AI 文章作成', queryTitle: '入力内容', completionResult: '生成結果', queryPlaceholder: '入力してください', @@ -52,11 +52,11 @@ const translation = { execution: '処理中', executions: '{{num}}回実行', copy: 'コピー', - resultTitle: 'AI生成結果', - noData: 'AIがコンテンツを生成します', - csvUploadTitle: 'CSVファイルをドロップするか', + resultTitle: 'AI 生成結果', + noData: 'AI がコンテンツを生成します', + csvUploadTitle: 'CSV ファイルをドロップするか', browse: 'ファイルを選択', - csvStructureTitle: 'CSV形式要件:', + csvStructureTitle: 'CSV 形式要件:', downloadTemplate: 'テンプレートを取得', field: '', batchFailed: { @@ -67,10 +67,10 @@ const translation = { errorMsg: { empty: 'ファイル内容が空です', fileStructNotMatch: 'ファイル形式が不正です', - emptyLine: '{{rowIndex}}行目: 内容が空です', - invalidLine: '{{rowIndex}}行目: {{varName}}の入力が必要です', - moreThanMaxLengthLine: '{{rowIndex}}行目: {{varName}}が制限長({{maxLength}})を超過', - atLeastOne: '1行以上のデータが必要です', + emptyLine: '{{rowIndex}}行目:内容が空です', + invalidLine: '{{rowIndex}}行目:{{varName}}の入力が必要です', + moreThanMaxLengthLine: '{{rowIndex}}行目:{{varName}}が制限長({{maxLength}})を超過', + atLeastOne: '1 行以上のデータが必要です', }, }, } diff --git a/web/i18n/ja-JP/time.ts b/web/i18n/ja-JP/time.ts index 09203a0cc2..6594533b2b 100644 --- a/web/i18n/ja-JP/time.ts +++ b/web/i18n/ja-JP/time.ts @@ -9,18 +9,18 @@ const translation = { Sun: '日曜日', }, months: { - November: '11月', - December: '12月', - March: '3月', - September: '9月', - July: '7月', - April: '4月', - February: '2月', - June: '6月', - January: '1月', - May: '5月', - August: '8月', - October: '10月', + November: '11 月', + December: '12 月', + March: '3 月', + September: '9 月', + July: '7 月', + April: '4 月', + February: '2 月', + June: '6 月', + January: '1 月', + May: '5 月', + August: '8 月', + October: '10 月', }, operation: { now: '今', diff --git a/web/i18n/ja-JP/tools.ts b/web/i18n/ja-JP/tools.ts index d8262a4a19..cf9dad95b3 100644 --- a/web/i18n/ja-JP/tools.ts +++ b/web/i18n/ja-JP/tools.ts @@ -1,7 +1,7 @@ const translation = { title: 'ツール', createCustomTool: 'カスタムツールを作成する', - customToolTip: 'Difyカスタムツールの詳細', + customToolTip: 'Dify カスタムツールの詳細', type: { all: 'すべて', builtIn: 'ツール', @@ -10,7 +10,7 @@ const translation = { }, contribute: { line1: '私は', - line2: 'Difyへのツールの貢献に興味があります。', + line2: 'Dify へのツールの貢献に興味があります。', viewGuide: 'ガイドを見る', }, author: '著者:', @@ -29,7 +29,7 @@ const translation = { added: '追加済', manageInTools: 'ツールリストに移動して管理する', emptyTitle: '利用可能なワークフローツールはありません', - emptyTip: '追加するには、「ワークフロー -> ツールとして公開 」に移動する', + emptyTip: '追加するには、「ワークフロー -> ツールとして公開」に移動する', emptyTitleCustom: 'カスタムツールはありません', emptyTipCustom: 'カスタムツールの作成', }, @@ -40,20 +40,20 @@ const translation = { name: '名前', toolNamePlaceHolder: 'ツール名を入力してください', nameForToolCall: 'ツールコールの名前', - nameForToolCallPlaceHolder: '機械認識に使用される名前, 例えば、getCurrentWeather、list_pets', + nameForToolCallPlaceHolder: '機械認識に使用される名前,例えば、getCurrentWeather、list_pets', nameForToolCallTip: '数字、文字、アンダースコアのみがサポートされます。', description: 'ツールの説明', descriptionPlaceholder: 'ツールの使い方の簡単な説明。例えば、特定の場所の温度を知るためなど。', schema: 'スキーマ', - schemaPlaceHolder: 'ここにOpenAPIスキーマを入力してください', - viewSchemaSpec: 'OpenAPI-Swagger仕様を表示する', - importFromUrl: 'URLからインポートする', + schemaPlaceHolder: 'ここに OpenAPI スキーマを入力してください', + viewSchemaSpec: 'OpenAPI-Swagger 仕様を表示する', + importFromUrl: 'URL からインポートする', importFromUrlPlaceHolder: 'https://...', - urlError: '有効なURLを入力してください', + urlError: '有効な URL を入力してください', examples: '例', exampleOptions: { - json: '天気(JSON)', - yaml: 'ペットストア(YAML)', + json: '天気 (JSON)', + yaml: 'ペットストア (YAML)', blankTemplate: '空白テンプレート', }, availableTools: { @@ -68,12 +68,12 @@ const translation = { authMethod: { title: '認証方法', type: '認証タイプ', - keyTooltip: 'HTTPヘッダーキー。アイデアがない場合は "Authorization" として残しておいてもかまいません。またはカスタム値に設定できます。', + keyTooltip: 'HTTP ヘッダーキー。アイデアがない場合は "Authorization" として残しておいてもかまいません。またはカスタム値に設定できます。', types: { none: 'なし', - api_key: 'APIキー', - apiKeyPlaceholder: 'APIキーのHTTPヘッダー名', - apiValuePlaceholder: 'APIキーを入力してください', + api_key: 'API キー', + apiKeyPlaceholder: 'API キーの HTTP ヘッダー名', + apiValuePlaceholder: 'API キーを入力してください', }, key: 'キー', value: '値', @@ -95,10 +95,10 @@ const translation = { method: 'メソッド', methodSetting: '設定', methodSettingTip: 'ユーザーがツール設定を入力する', - methodParameter: 'LLM入力', + methodParameter: 'LLM 入力', methodParameterTip: 'LLM は推論中に入力されます', label: 'ラベル', - labelPlaceholder: 'ラベルを選択します(オプション)', + labelPlaceholder: 'ラベルを選択します (オプション)', description: '説明', descriptionPlaceholder: 'パラメータの意味の説明', }, @@ -136,7 +136,7 @@ const translation = { }, noCustomTool: { title: 'カスタムツールがありません!', - content: 'AIアプリを構築するためのカスタムツールをここで追加および管理します。', + content: 'AI アプリを構築するためのカスタムツールをここで追加および管理します。', createTool: 'ツールを作成する', }, noSearchRes: { diff --git a/web/i18n/ja-JP/workflow.ts b/web/i18n/ja-JP/workflow.ts index 8495a7dfd5..1320e7f3b6 100644 --- a/web/i18n/ja-JP/workflow.ts +++ b/web/i18n/ja-JP/workflow.ts @@ -20,7 +20,7 @@ const translation = { goBackToEdit: '編集に戻る', conversationLog: '会話ログ', features: '機能', - featuresDescription: 'Webアプリの操作性を向上させる機能', + featuresDescription: 'Web アプリの操作性を向上させる機能', ImageUploadLegacyTip: '開始フォームでファイル型変数が作成可能になりました。画像アップロード機能は今後サポート終了となります。', fileUploadTip: '画像アップロード機能がファイルアップロードに拡張されました', featuresDocLink: '詳細を見る', @@ -36,7 +36,7 @@ const translation = { runApp: 'アプリを実行', batchRunApp: 'アプリを一括実行', openInExplore: '探索ページで開く', - accessAPIReference: 'APIリファレンス', + accessAPIReference: 'API リファレンス', embedIntoSite: 'サイトに埋め込む', addTitle: 'タイトルを追加...', addDescription: '説明を追加...', @@ -45,7 +45,7 @@ const translation = { variableNamePlaceholder: '変数名を入力', setVarValuePlaceholder: '変数値を設定', needConnectTip: '接続されていないステップがあります', - maxTreeDepth: '1ブランチあたりの最大ノード数:{{depth}}', + maxTreeDepth: '1 ブランチあたりの最大ノード数:{{depth}}', needEndNode: '終了ブロックを追加する必要があります', needAnswerNode: '回答ブロックを追加する必要があります', workflowProcess: 'ワークフロー処理', @@ -59,10 +59,10 @@ const translation = { processData: 'データ処理', input: '入力', output: '出力', - jinjaEditorPlaceholder: '「/」または 「{」で変数挿入', + jinjaEditorPlaceholder: '「/」または「{」で変数挿入', viewOnly: '閲覧のみ', showRunHistory: '実行履歴を表示', - enableJinja: 'Jinjaテンプレートを有効化', + enableJinja: 'Jinja テンプレートを有効化', learnMore: '詳細を見る', copy: 'コピー', duplicate: '複製', @@ -71,9 +71,9 @@ const translation = { pointerMode: 'ポインターモード', handMode: 'ハンドモード', exportImage: '画像を出力', - exportPNG: 'PNGで出力', - exportJPEG: 'JPEGで出力', - exportSVG: 'SVGで出力', + exportPNG: 'PNG で出力', + exportJPEG: 'JPEG で出力', + exportSVG: 'SVG で出力', model: 'モデル', workflowAsTool: 'ワークフローをツールとして公開する', configureRequired: '設定が必要', @@ -82,14 +82,14 @@ const translation = { workflowAsToolTip: 'ワークフロー更新後はツールの再設定が必要です', viewDetailInTracingPanel: '詳細を表示', syncingData: 'データ同期中。。。', - importDSL: 'DSLをインポート', + importDSL: 'DSL をインポート', importDSLTip: '現在の下書きは上書きされます。インポート前にワークフローをエクスポートしてバックアップしてください', backupCurrentDraft: '現在の下書きをバックアップ', - chooseDSL: 'DSL(yml)ファイルを選択', + chooseDSL: 'DSL(yml) ファイルを選択', overwriteAndImport: '上書きしてインポート', importFailure: 'インポート失敗', importWarning: '注意事項', - importWarningDetails: 'DSLバージョンの違いにより機能に影響が出る可能性があります', + importWarningDetails: 'DSL バージョンの違いにより機能に影響が出る可能性があります', importSuccess: 'インポート成功', parallelRun: '並列実行', parallelTip: { @@ -116,7 +116,7 @@ const translation = { }, env: { envPanelTitle: '環境変数', - envDescription: '環境変数は、個人情報や認証情報を格納するために使用することができます。これらは読み取り専用であり、DSLファイルからエクスポートする際には分離されます。', + envDescription: '環境変数は、個人情報や認証情報を格納するために使用することができます。これらは読み取り専用であり、DSL ファイルからエクスポートする際には分離されます。', envPanelButton: '環境変数を追加', modal: { title: '環境変数を追加', @@ -131,7 +131,7 @@ const translation = { export: { title: 'シークレット環境変数をエクスポートしますか?', checkbox: 'シークレット値を含む', - ignore: 'DSLをエクスポート', + ignore: 'DSL をエクスポート', export: 'シークレット値付きでエクスポート', }, }, @@ -150,7 +150,7 @@ const translation = { valuePlaceholder: 'デフォルト値、設定しない場合は空白にしてください', description: '説明', descriptionPlaceholder: '変数の説明を入力', - editInJSON: 'JSONで編集', + editInJSON: 'JSON で編集', oneByOne: '個別追加', editInForm: 'フォームで編集', arrayValue: '値', @@ -198,7 +198,7 @@ const translation = { variableValue: '変数値', code: 'コード', model: 'モデル', - rerankModel: 'Rerankモデル', + rerankModel: 'Rerank モデル', visionVariable: 'ビジョン変数', }, invalidVariable: '無効な変数です', @@ -241,7 +241,7 @@ const translation = { 'if-else': 'IF/ELSE', 'code': 'コード実行', 'template-transform': 'テンプレート', - 'http-request': 'HTTPリクエスト', + 'http-request': 'HTTP リクエスト', 'variable-assigner': '変数代入器', 'variable-aggregator': '変数集約器', 'assigner': '変数代入', @@ -261,11 +261,11 @@ const translation = { 'answer': 'チャットダイアログの返答内容を定義します。', 'llm': '大規模言語モデルを呼び出して質問回答や自然言語処理を実行します。', 'knowledge-retrieval': 'ナレッジベースからユーザー質問に関連するテキストを検索します。', - 'question-classifier': '質問の分類条件を定義し、LLMが分類に基づいて対話フローを制御します。', - 'if-else': 'if/else条件でワークフローを2つの分岐に分割します。', - 'code': 'Python/NodeJSコードを実行してカスタムロジックを実装します。', - 'template-transform': 'Jinjaテンプレート構文でデータを文字列に変換します。', - 'http-request': 'HTTPリクエストを送信できます。', + 'question-classifier': '質問の分類条件を定義し、LLM が分類に基づいて対話フローを制御します。', + 'if-else': 'if/else 条件でワークフローを 2 つの分岐に分割します。', + 'code': 'Python/NodeJS コードを実行してカスタムロジックを実装します。', + 'template-transform': 'Jinja テンプレート構文でデータを文字列に変換します。', + 'http-request': 'HTTP リクエストを送信できます。', 'variable-assigner': '複数分岐の変数を集約し、下流ノードの設定を統一します。', 'assigner': '書き込み可能な変数(例:会話変数)への値の割り当てを行います。', 'variable-aggregator': '複数分岐の変数を集約し、下流ノードの設定を統一します。', @@ -273,14 +273,14 @@ const translation = { 'loop': '終了条件達成まで、または最大反復回数までロジックを繰り返します。', 'loop-end': '「break」相当の機能です。このノードに設定項目はなく、ループ処理中にこのノードに到達すると即時終了します。', 'parameter-extractor': '自然言語から構造化パラメータを抽出し、後続処理で利用します。', - 'document-extractor': 'アップロード文書をLLM処理用に最適化されたテキストに変換します。', + 'document-extractor': 'アップロード文書を LLM 処理用に最適化されたテキストに変換します。', 'list-operator': '配列のフィルタリングやソート処理を行います。', 'agent': '大規模言語モデルを活用した質問応答や自然言語処理を実行します。', }, operator: { zoomIn: '拡大', zoomOut: '縮小', - zoomTo50: '50%サイズ', + zoomTo50: '50% サイズ', zoomTo100: '等倍表示', zoomToFit: '画面に合わせる', }, @@ -336,7 +336,7 @@ const translation = { defaultValue: { title: 'デフォルト値', desc: '例外発生時のデフォルト出力', - tip: '例外発生時に返される値:', + tip: '例外発生時に返される値:', inLog: 'ノード例外 - デフォルト値を出力', output: 'デフォルト値出力', }, @@ -363,7 +363,7 @@ const translation = { retryFailedTimes: '{{times}}回再試行失敗', times: '回', ms: 'ミリ秒', - retries: '再試行回数: {{num}}', + retries: '再試行回数:{{num}}', }, }, start: { @@ -398,7 +398,7 @@ const translation = { outputVars: '出力変数', }, llm: { - model: 'AIモデル', + model: 'AI モデル', variables: '変数', context: 'コンテキスト', contextTooltip: 'ナレッジベースをコンテキストとして利用', @@ -424,17 +424,17 @@ const translation = { singleRun: { variable: '変数', }, - sysQueryInUser: 'ユーザーメッセージにsys.queryを含めてください', + sysQueryInUser: 'ユーザーメッセージに sys.query を含めてください', jsonSchema: { title: '構造化データスキーマ', instruction: '指示', - promptTooltip: 'テキスト説明から標準JSONスキーマを自動生成できます。', - promptPlaceholder: 'JSONスキーマを入力...', + promptTooltip: 'テキスト説明から標準 JSON スキーマを自動生成できます。', + promptPlaceholder: 'JSON スキーマを入力...', generate: '生成', - import: 'JSONインポート', + import: 'JSON インポート', generateJsonSchema: 'スキーマ生成', - generationTip: '自然言語で簡単にJSONスキーマを作成可能です。', - generating: 'JSONスキーマを生成中...', + generationTip: '自然言語で簡単に JSON スキーマを作成可能です。', + generating: 'JSON スキーマを生成中...', generatedResult: '生成結果', resultTip: 'こちらが生成された結果です。ご満足いただけない場合は、前の画面に戻ってプロンプトを修正できます。', back: '前に戻る', @@ -462,7 +462,7 @@ const translation = { content: 'セグメント内容', title: 'セグメントタイトル', icon: 'セグメントアイコン', - url: 'セグメントURL', + url: 'セグメント URL', metadata: 'メタデータ', }, metadata: { @@ -497,9 +497,9 @@ const translation = { http: { inputVars: '入力変数', api: 'API', - apiPlaceholder: 'URLを入力(変数使用時は"/"を入力)', + apiPlaceholder: 'URL を入力(変数使用時は"/"を入力)', extractListPlaceholder: 'リスト番号を入力(変数使用時は"/"を入力)', - notStartWithHttp: 'APIは http:// または https:// で始まってください', + notStartWithHttp: 'API は http:// または https:// で始まってください', key: 'キー', type: 'タイプ', value: '値', @@ -519,12 +519,12 @@ const translation = { 'authorization': '認証', 'authorizationType': '認証タイプ', 'no-auth': 'なし', - 'api-key': 'APIキー', - 'auth-type': 'API認証タイプ', + 'api-key': 'API キー', + 'auth-type': 'API 認証タイプ', 'basic': 'ベーシック', 'bearer': 'Bearer', 'custom': 'カスタム', - 'api-key-title': 'APIキー', + 'api-key-title': 'API キー', 'header': 'ヘッダー', }, insertVarPlaceholder: '変数を挿入するには\'/\'を入力してください', @@ -538,8 +538,8 @@ const translation = { writePlaceholder: '書き込みタイムアウト(秒)', }, curl: { - title: 'cURLからインポート', - placeholder: 'ここにcURL文字列を貼り付けます', + title: 'cURL からインポート', + placeholder: 'ここに cURL 文字列を貼り付けます', }, }, code: { @@ -552,7 +552,7 @@ const translation = { templateTransform: { inputVars: '入力変数', code: 'コード', - codeSupportTip: 'Jinja2のみをサポートしています', + codeSupportTip: 'Jinja2 のみをサポートしています', outputVars: { output: '変換されたコンテンツ', }, @@ -560,7 +560,7 @@ const translation = { ifElse: { if: 'もし', else: 'それ以外', - elseDescription: 'IF条件が満たされない場合に実行するロジックを定義します。', + elseDescription: 'IF 条件が満たされない場合に実行するロジックを定義します。', and: 'かつ', or: 'または', operator: '演算子', @@ -575,7 +575,7 @@ const translation = { 'empty': '空', 'not empty': '空でない', 'null': 'null', - 'not null': 'nullでない', + 'not null': 'null でない', 'regex match': '正規表現マッチ', 'in': '含まれている', 'not in': '含まれていない', @@ -623,7 +623,7 @@ const translation = { assigner: { 'assignedVariable': '代入された変数', 'writeMode': '書き込みモード', - 'writeModeTip': '代入された変数が配列の場合, 末尾に追記モードを追加する。', + 'writeModeTip': '代入された変数が配列の場合,末尾に追記モードを追加する。', 'over-write': '上書き', 'append': '追記', 'plus': 'プラス', @@ -660,11 +660,11 @@ const translation = { files: { title: 'ツールが生成したファイル', type: 'サポートタイプ。現在は画像のみサポートされています', - transfer_method: '転送方法。値はremote_urlまたはlocal_fileです', - url: '画像URL', - upload_file_id: 'アップロードファイルID', + transfer_method: '転送方法。値は remote_url または local_file です', + url: '画像 URL', + upload_file_id: 'アップロードファイル ID', }, - json: 'ツールで生成されたJSON', + json: 'ツールで生成された JSON', }, authorize: '認証する', }, @@ -705,7 +705,7 @@ const translation = { advancedSetting: '高度な設定', reasoningMode: '推論モード', reasoningModeTip: '関数呼び出しやプロンプトの指示に応答するモデルの能力に基づいて、適切な推論モードを選択できます。', - isSuccess: '成功。成功した場合の値は1、失敗した場合の値は0です。', + isSuccess: '成功。成功した場合の値は 1、失敗した場合の値は 0 です。', errorReason: 'エラーの理由', }, iteration: { @@ -732,7 +732,7 @@ const translation = { parallelModeEnableDesc: '並列モードでは、イテレーション内のタスクは並列実行をサポートします。これは、右側のプロパティパネルで構成できます。', parallelModeEnableTitle: 'パラレルモード有効', MaxParallelismDesc: '最大並列処理は、1 回の反復で同時に実行されるタスクの数を制御するために使用されます。', - answerNodeWarningDesc: '並列モードの警告: 応答ノード、会話変数の割り当て、およびイテレーション内の永続的な読み取り/書き込み操作により、例外が発生する可能性があります。', + answerNodeWarningDesc: '並列モードの警告:応答ノード、会話変数の割り当て、およびイテレーション内の永続的な読み取り/書き込み操作により、例外が発生する可能性があります。', }, loop: { deleteTitle: 'ループノードを削除しますか?', @@ -745,7 +745,7 @@ const translation = { breakCondition: 'ループ終了条件', breakConditionTip: 'ループ内の変数やセッション変数を参照し、終了条件を設定できます。', loopMaxCount: '最大ループ回数', - loopMaxCountError: '最大ループ回数は1から{{maxCount}}の範囲で正しく入力してください。', + loopMaxCountError: '最大ループ回数は 1 から{{maxCount}}の範囲で正しく入力してください。', errorResponseMethod: 'エラー対応方法', ErrorMethod: { operationTerminated: 'エラー時に処理を終了', @@ -758,10 +758,10 @@ const translation = { setLoopVariables: 'ループスコープ内で変数を設定', variableName: '変数名', inputMode: '入力モード', - exitConditionTip: 'ループノードには少なくとも1つの終了条件が必要です', + exitConditionTip: 'ループノードには少なくとも 1 つの終了条件が必要です', loopNode: 'ループノード', - currentLoopCount: '現在のループ回数: {{count}}', - totalLoopCount: '総ループ回数: {{count}}', + currentLoopCount: '現在のループ回数:{{count}}', + totalLoopCount: '総ループ回数:{{count}}', error_other: '{{count}} エラー', error_one: '{{count}} エラー', comma: ',', @@ -791,7 +791,7 @@ const translation = { }, inputVar: '入力変数', learnMore: '詳細はこちら', - supportFileTypes: 'サポートするファイルタイプ: {{types}}。', + supportFileTypes: 'サポートするファイルタイプ:{{types}}。', }, listFilter: { outputVars: { @@ -799,7 +799,7 @@ const translation = { first_record: '最初のレコード', result: 'フィルター結果', }, - limit: 'トップN', + limit: 'トップ N', asc: 'ASC', filterCondition: 'フィルター条件', filterConditionKey: 'フィルター条件キー', @@ -809,7 +809,7 @@ const translation = { filterConditionComparisonOperator: 'フィルター条件を比較オペレーター', inputVar: '入力変数', desc: 'DESC', - extractsCondition: 'N個のアイテムを抽出します', + extractsCondition: 'N 個のアイテムを抽出します', }, agent: { strategy: { @@ -828,7 +828,7 @@ const translation = { modelNotInMarketplace: { manageInPlugins: 'プラグインを管理する', title: 'モデルがインストールされていません', - desc: 'このモデルはローカルまたはGitHubリポジトリからインストールされます。インストール後にご利用ください。', + desc: 'このモデルはローカルまたは GitHub リポジトリからインストールされます。インストール後にご利用ください。', }, modelNotSupport: { title: 'サポートされていないモデル', @@ -840,14 +840,14 @@ const translation = { }, outputVars: { files: { - url: '画像のURL', + url: '画像の URL', type: 'サポートタイプ。現在はサポート画像のみ', - upload_file_id: 'ファイルIDをアップロード', - transfer_method: '転送方法。値はremote_urlまたはlocal_fileです。', + upload_file_id: 'ファイル ID をアップロード', + transfer_method: '転送方法。値は remote_url または local_file です。', title: 'エージェント生成ファイル', }, text: 'エージェント生成コンテンツ', - json: 'エージェント生成のJSON', + json: 'エージェント生成の JSON', }, checkList: { strategyNotSelected: '戦略が選択されていません', @@ -875,9 +875,9 @@ const translation = { toolbox: 'ツールボックス', pluginNotInstalled: 'このプラグインはインストールされていません', strategyNotFoundDescAndSwitchVersion: 'インストールされたプラグインのバージョンはこの戦略を提供していません。バージョンを切り替えるにはクリックしてください。', - pluginNotInstalledDesc: 'このプラグインはGitHubからインストールされています。再インストールするにはプラグインに移動してください。', + pluginNotInstalledDesc: 'このプラグインは GitHub からインストールされています。再インストールするにはプラグインに移動してください。', unsupportedStrategy: 'サポートされていない戦略', - pluginNotFoundDesc: 'このプラグインはGitHubからインストールされています。再インストールするにはプラグインに移動してください。', + pluginNotFoundDesc: 'このプラグインは GitHub からインストールされています。再インストールするにはプラグインに移動してください。', strategyNotFoundDesc: 'インストールされたプラグインのバージョンは、この戦略を提供していません。', }, }, diff --git a/web/i18n/ko-KR/app-api.ts b/web/i18n/ko-KR/app-api.ts index 810e67a875..4f8ac14d86 100644 --- a/web/i18n/ko-KR/app-api.ts +++ b/web/i18n/ko-KR/app-api.ts @@ -16,7 +16,7 @@ const translation = { never: '없음', apiKeyModal: { apiSecretKey: 'API 비밀 키', - apiSecretKeyTips: 'API 키를 보호하여 API의 남용을 방지하십시오. 프런트엔드 코드에서 평문으로 사용하지 마세요. :)', + apiSecretKeyTips: 'API 키를 보호하여 API 의 남용을 방지하십시오. 프런트엔드 코드에서 평문으로 사용하지 마세요. :)', createNewSecretKey: '새로운 비밀 키 생성', secretKey: '비밀 키', created: '생성 날짜', @@ -30,43 +30,43 @@ const translation = { }, completionMode: { title: '완성 모드 API', - info: '문서, 요약, 번역 등 고품질 텍스트 생성을 위해 사용자 입력을 사용하는 완성 메시지 API를 사용합니다. 텍스트 생성은 Dify Prompt Engineering에서 설정한 모델 매개변수와 프롬프트 템플릿에 의존합니다.', + info: '문서, 요약, 번역 등 고품질 텍스트 생성을 위해 사용자 입력을 사용하는 완성 메시지 API 를 사용합니다. 텍스트 생성은 Dify Prompt Engineering 에서 설정한 모델 매개변수와 프롬프트 템플릿에 의존합니다.', createCompletionApi: '완성 메시지 생성', createCompletionApiTip: '질의 응답 모드를 지원하기 위해 완성 메시지를 생성합니다.', inputsTips: - '(선택 사항) Prompt Eng의 변수에 해당하는 키-값 쌍으로 사용자 입력 필드를 제공합니다. 키는 변수 이름이고 값은 매개변수 값입니다. 필드 유형이 Select인 경우 전송되는 값은 미리 설정된 선택 사항 중 하나여야 합니다.', + '(선택 사항) Prompt Eng 의 변수에 해당하는 키 - 값 쌍으로 사용자 입력 필드를 제공합니다. 키는 변수 이름이고 값은 매개변수 값입니다. 필드 유형이 Select 인 경우 전송되는 값은 미리 설정된 선택 사항 중 하나여야 합니다.', queryTips: '사용자 입력 텍스트 내용.', blocking: '블로킹 유형으로 실행이 완료되고 결과가 반환될 때까지 대기합니다. (처리가 오래 걸리면 요청이 중단될 수 있습니다)', - streaming: '스트리밍 반환. SSE(Server-Sent Events)를 기반으로 하는 스트리밍 반환 구현.', - messageFeedbackApi: '메시지 피드백(좋아요)', + streaming: '스트리밍 반환. SSE(Server-Sent Events) 를 기반으로 하는 스트리밍 반환 구현.', + messageFeedbackApi: '메시지 피드백 (좋아요)', messageFeedbackApiTip: '엔드 사용자 대신 수신된 메시지를 "좋아요" 또는 "좋아요"로 평가합니다. 이 데이터는 로그 및 주석 페이지에 표시되며 향후 모델 세부 조정에 사용됩니다.', messageIDTip: '메시지 ID', - ratingTip: '좋아요 또는 좋아요, null은 취소', + ratingTip: '좋아요 또는 좋아요, null 은 취소', parametersApi: '애플리케이션 매개변수 정보 가져오기', parametersApiTip: '변수 이름, 필드 이름, 유형, 기본값을 포함한 설정된 입력 매개변수를 가져옵니다. 일반적으로 이러한 필드는 양식에 표시하거나 클라이언트 로드 후에 기본값을 입력하는 데 사용됩니다.', }, chatMode: { title: '채팅 모드 API', - info: '질의 응답 형식을 사용하는 다목적 대화형 응용 프로그램에는 채팅 메시지 API를 호출하여 대화를 시작합니다. 반환된 conversation_id를 전달하여 계속된 대화를 유지합니다. 응답 매개변수 및 템플릿은 Dify Prompt Eng의 설정에 의존합니다.', + info: '질의 응답 형식을 사용하는 다목적 대화형 응용 프로그램에는 채팅 메시지 API 를 호출하여 대화를 시작합니다. 반환된 conversation_id 를 전달하여 계속된 대화를 유지합니다. 응답 매개변수 및 템플릿은 Dify Prompt Eng 의 설정에 의존합니다.', createChatApi: '채팅 메시지 생성', createChatApiTip: '새로운 대화 메시지를 생성하거나 기존 대화를 계속합니다.', inputsTips: - '(선택 사항) Prompt Eng의 변수에 해당하는 키-값 쌍으로 사용자 입력 필드를 제공합니다. 키는 변수 이름이고 값은 매개변수 값입니다. 필드 유형이 Select인 경우 전송되는 값은 미리 설정된 선택 사항 중 하나여야 합니다.', + '(선택 사항) Prompt Eng 의 변수에 해당하는 키 - 값 쌍으로 사용자 입력 필드를 제공합니다. 키는 변수 이름이고 값은 매개변수 값입니다. 필드 유형이 Select 인 경우 전송되는 값은 미리 설정된 선택 사항 중 하나여야 합니다.', queryTips: '사용자 입력/질문 내용', blocking: '블로킹 유형으로 실행이 완료되고 결과가 반환될 때까지 대기합니다. (처리가 오래 걸리면 요청이 중단될 수 있습니다)', - streaming: '스트리밍 반환. SSE(Server-Sent Events)를 기반으로 하는 스트리밍 반환 구현.', - conversationIdTip: '(선택 사항) 대화 ID: 처음 대화의 경우 비워두고, 계속된 경우 컨텍스트에서 conversation_id를 전달합니다.', - messageFeedbackApi: '메시지 피드백(좋아요)', + streaming: '스트리밍 반환. SSE(Server-Sent Events) 를 기반으로 하는 스트리밍 반환 구현.', + conversationIdTip: '(선택 사항) 대화 ID: 처음 대화의 경우 비워두고, 계속된 경우 컨텍스트에서 conversation_id 를 전달합니다.', + messageFeedbackApi: '메시지 피드백 (좋아요)', messageFeedbackApiTip: '엔드 사용자 대신 수신된 메시지를 "좋아요" 또는 "좋아요"로 평가합니다. 이 데이터는 로그 및 주석 페이지에 표시되며 향후 모델 세부 조정에 사용됩니다.', messageIDTip: '메시지 ID', - ratingTip: '좋아요 또는 좋아요, null은 취소', + ratingTip: '좋아요 또는 좋아요, null 은 취소', chatMsgHistoryApi: '채팅 메시지 기록 가져오기', chatMsgHistoryApiTip: '첫 번째 페이지는 최신의 "limit" 바를 반환합니다. 역순입니다.', chatMsgHistoryConversationIdTip: '대화 ID', chatMsgHistoryFirstId: '현재 페이지의 첫 번째 채팅 레코드의 ID. 기본값은 없음입니다.', chatMsgHistoryLimit: '한 번에 반환되는 채팅 수', conversationsListApi: '대화 목록 가져오기', - conversationsListApiTip: '현재 사용자의 세션 목록을 가져옵니다. 기본적으로 최근 20개의 세션이 반환됩니다.', + conversationsListApiTip: '현재 사용자의 세션 목록을 가져옵니다. 기본적으로 최근 20 개의 세션이 반환됩니다.', conversationsListFirstIdTip: '현재 페이지의 마지막 레코드의 ID, 기본값은 없음입니다.', conversationsListLimitTip: '한 번에 반환되는 채팅 수', conversationRenamingApi: '대화 이름 변경', diff --git a/web/i18n/ko-KR/app-debug.ts b/web/i18n/ko-KR/app-debug.ts index bafe0bf8d8..290ccb0b01 100644 --- a/web/i18n/ko-KR/app-debug.ts +++ b/web/i18n/ko-KR/app-debug.ts @@ -39,8 +39,8 @@ const translation = { settingBtn: '설정으로 이동', }, trailUseGPT4Info: { - title: '현재 gpt-4는 지원되지 않습니다', - description: 'gpt-4를 사용하려면 API 키를 설정해야 합니다.', + title: '현재 gpt-4 는 지원되지 않습니다', + description: 'gpt-4 를 사용하려면 API 키를 설정해야 합니다.', }, feature: { groupChat: { @@ -52,12 +52,12 @@ const translation = { }, conversationOpener: { title: '대화 시작', - description: '채팅 앱에서 AI가 사용자에게 처음으로 적극적으로 말을 건다면 일반적으로 환영 메시지로 사용됩니다.', + description: '채팅 앱에서 AI 가 사용자에게 처음으로 적극적으로 말을 건다면 일반적으로 환영 메시지로 사용됩니다.', }, suggestedQuestionsAfterAnswer: { title: '팔로우업', description: '다음 질문 제안을 설정하면 사용자에게 더 나은 채팅이 제공됩니다.', - resDes: '사용자의 다음 질문에 대한 3가지 제안.', + resDes: '사용자의 다음 질문에 대한 3 가지 제안.', tryToAsk: '질문해보세요', }, moreLikeThis: { @@ -162,7 +162,7 @@ const translation = { }, moderation: { title: '콘텐츠 모더레이션', - description: '모더레이션 API를 사용하거나 기밀 단어 목록을 유지함으로써 모델 출력을 안전하게 합니다.', + description: '모더레이션 API 를 사용하거나 기밀 단어 목록을 유지함으로써 모델 출력을 안전하게 합니다.', allEnabled: '입력/출력 콘텐츠가 모두 활성화되어 있습니다', inputEnabled: '입력 콘텐츠가 활성화되어 있습니다', outputEnabled: '출력 콘텐츠가 활성화되어 있습니다', @@ -178,7 +178,7 @@ const translation = { keywords: '키워드', }, keywords: { - tip: '한 줄에 하나씩, 줄 바꿈으로 입력하세요. 한 줄 당 최대 100자.', + tip: '한 줄에 하나씩, 줄 바꿈으로 입력하세요. 한 줄 당 최대 100 자.', placeholder: '한 줄씩 입력하세요', line: '줄', }, @@ -188,7 +188,7 @@ const translation = { preset: '프리셋 응답', placeholder: '프리셋 응답 내용을 입력하세요', condition: '최소한 하나의 입력 및 출력 콘텐츠를 모더레이션합니다', - fromApi: '프리셋 응답은 API에서 반환됩니다', + fromApi: '프리셋 응답은 API 에서 반환됩니다', errorMessage: '프리셋 응답은 비워둘 수 없습니다', supportMarkdown: '마크다운이 지원됩니다', }, @@ -201,10 +201,10 @@ const translation = { }, automatic: { title: '자동 어플리케이션 오케스트레이션', - description: '시나리오를 설명하세요. Dify가 어플리케이션을 자동으로 오케스트레이션 합니다.', + description: '시나리오를 설명하세요. Dify 가 어플리케이션을 자동으로 오케스트레이션 합니다.', intendedAudience: '누가 대상이 되는지 설명하세요.', intendedAudiencePlaceHolder: '예: 학생', - solveProblem: '어떤 문제를 AI가 해결할 것으로 예상하나요?', + solveProblem: '어떤 문제를 AI 가 해결할 것으로 예상하나요?', solveProblemPlaceHolder: '예: 학업 성적 평가', generate: '생성', audiencesRequired: '대상이 필요합니다', @@ -231,7 +231,7 @@ const translation = { }, chatSubTitle: '단계', completionSubTitle: '접두사 프롬프트', - promptTip: '프롬프트는 AI의 응답을 지시하고 제한하여 유도합니다. {{input}}과 같은 변수를 삽입하세요. 이 프롬프트는 사용자에게 표시되지 않습니다.', + promptTip: '프롬프트는 AI 의 응답을 지시하고 제한하여 유도합니다. {{input}}과 같은 변수를 삽입하세요. 이 프롬프트는 사용자에게 표시되지 않습니다.', formattingChangedTitle: '포맷이 변경되었습니다', formattingChangedText: '포맷을 변경하면 디버그 영역이 재설정됩니다. 계속하시겠습니까?', variableTitle: '변수', @@ -249,7 +249,7 @@ const translation = { }, varKeyError: { canNoBeEmpty: '{{key}}가 필요합니다', - tooLong: '{{key}}가 너무 깁니다. 30자를 넘을 수 없습니다', + tooLong: '{{key}}가 너무 깁니다. 30 자를 넘을 수 없습니다', notValid: '{{key}}가 유효하지 않습니다. 문자, 숫자, 밑줄만 포함할 수 있습니다', notStartWithNumber: '{{key}}는 숫자로 시작할 수 없습니다', keyAlreadyExists: '{{key}}는 이미 존재합니다', @@ -294,9 +294,9 @@ const translation = { visionSettings: { title: '비전 설정', resolution: '해상도', - resolutionTooltip: `저해상도는 모델에게 512 x 512 해상도의 저해상도 이미지를 제공하여 65 토큰의 예산으로 이미지를 표현합니다. 이로 인해 API는 더 빠른 응답을 제공하며 높은 세부 정보가 필요한 경우 토큰 소모를 늘립니다. + resolutionTooltip: `저해상도는 모델에게 512 x 512 해상도의 저해상도 이미지를 제공하여 65 토큰의 예산으로 이미지를 표현합니다. 이로 인해 API 는 더 빠른 응답을 제공하며 높은 세부 정보가 필요한 경우 토큰 소모를 늘립니다. \n - 고해상도는 먼저 모델에게 저해상도 이미지를 보여주고, 그 후 입력 이미지 크기에 따라 512px의 정사각형 세부 사진을 만듭니다. 각 세부 사진에 대해 129 토큰의 예산을 사용합니다.`, + 고해상도는 먼저 모델에게 저해상도 이미지를 보여주고, 그 후 입력 이미지 크기에 따라 512px 의 정사각형 세부 사진을 만듭니다. 각 세부 사진에 대해 129 토큰의 예산을 사용합니다.`, high: '고', low: '저', uploadMethod: '업로드 방식', @@ -363,12 +363,12 @@ const translation = { }, retrieveMultiWay: { title: '멀티패스 리트리벌', - description: '사용자 의도에 따라 모든 지식을 쿼리하고, 관련 텍스트를 여러 소스에서 가져와 다시 순위를 매긴 후 사용자 쿼리에 가장 적합한 결과를 선택합니다. 재순위 모델 API의 구성이 필요합니다.', + description: '사용자 의도에 따라 모든 지식을 쿼리하고, 관련 텍스트를 여러 소스에서 가져와 다시 순위를 매긴 후 사용자 쿼리에 가장 적합한 결과를 선택합니다. 재순위 모델 API 의 구성이 필요합니다.', }, rerankModelRequired: '재순위 모델이 필요합니다', params: '매개변수', top_k: '상위 K', - top_kTip: '사용자 질문에 가장 유사한 청크를 필터링하는 데 사용됩니다. 시스템은 선택한 모델의 max_tokens에 따라 동적으로 상위 K 값을 조정합니다.', + top_kTip: '사용자 질문에 가장 유사한 청크를 필터링하는 데 사용됩니다. 시스템은 선택한 모델의 max_tokens 에 따라 동적으로 상위 K 값을 조정합니다.', score_threshold: '점수 임계값', score_thresholdTip: '청크 필터링의 유사성 임계값을 설정하는 데 사용됩니다.', retrieveChangeTip: '인덱스 모드 및 리트리벌 모드를 변경하면 이 지식과 관련된 애플리케이션에 영향을 줄 수 있습니다.', @@ -409,7 +409,7 @@ const translation = { promptPlaceholder: '여기에 프롬프트를 입력하세요', tools: { name: '도구', - description: '도구를 사용하여 인터넷 검색이나 과학적 계산 등 LLM의 기능을 확장할 수 있습니다', + description: '도구를 사용하여 인터넷 검색이나 과학적 계산 등 LLM 의 기능을 확장할 수 있습니다', enabled: '활성화됨', }, }, diff --git a/web/i18n/ko-KR/app-log.ts b/web/i18n/ko-KR/app-log.ts index 4017692f5c..6ed33b3c1c 100644 --- a/web/i18n/ko-KR/app-log.ts +++ b/web/i18n/ko-KR/app-log.ts @@ -49,7 +49,7 @@ const translation = { dislike: '좋아요 취소', addAnnotation: '향상 추가', editAnnotation: '향상 편집', - annotationPlaceholder: 'AI가 응답할 것으로 예상하는 답변을 입력하여 향후 모델 세부 조정 및 텍스트 생성 품질 지속적 향상을 위해 개선할 수 있습니다.', + annotationPlaceholder: 'AI 가 응답할 것으로 예상하는 답변을 입력하여 향후 모델 세부 조정 및 텍스트 생성 품질 지속적 향상을 위해 개선할 수 있습니다.', }, variables: '변수', uploadImages: '업로드된 이미지', @@ -58,10 +58,10 @@ const translation = { filter: { period: { today: '오늘', - last7days: '지난 7일', - last4weeks: '지난 4주', - last3months: '지난 3개월', - last12months: '지난 12개월', + last7days: '지난 7 일', + last4weeks: '지난 4 주', + last3months: '지난 3 개월', + last12months: '지난 12 개월', monthToDate: '월 초부터 오늘까지', quarterToDate: '분기 초부터 오늘까지', yearToDate: '연 초부터 오늘까지', @@ -77,7 +77,7 @@ const translation = { ascending: '오름차순', }, workflowTitle: '워크플로우 로그', - workflowSubtitle: '이 로그는 Automate의 작업을 기록했습니다.', + workflowSubtitle: '이 로그는 Automate 의 작업을 기록했습니다.', runDetail: { title: '대화 로그', workflowTitle: '로그 세부 정보', diff --git a/web/i18n/ko-KR/app-overview.ts b/web/i18n/ko-KR/app-overview.ts index 3a9c56367c..136e472a24 100644 --- a/web/i18n/ko-KR/app-overview.ts +++ b/web/i18n/ko-KR/app-overview.ts @@ -25,7 +25,7 @@ const translation = { callTimes: '요청 횟수', usedToken: '사용된 토큰', setAPIBtn: '모델 제공자 설정으로 이동', - tryCloud: '또는 Dify의 클라우드 버전을 무료로 체험해보세요', + tryCloud: '또는 Dify 의 클라우드 버전을 무료로 체험해보세요', }, overview: { title: '개요', @@ -34,7 +34,7 @@ const translation = { accessibleAddress: '공개 URL', preview: '미리보기', regenerate: '재생성', - regenerateNotice: '공개 URL을 재생성하시겠습니까?', + regenerateNotice: '공개 URL 을 재생성하시겠습니까?', preUseReminder: '계속하기 전에 웹앱을 활성화하세요.', settings: { entry: '설정', @@ -48,21 +48,21 @@ const translation = { title: '워크플로 단계', show: '표시', hide: '숨기기', - showDesc: 'WebApp에서 워크플로 세부 정보 표시 또는 숨기기', + showDesc: 'WebApp 에서 워크플로 세부 정보 표시 또는 숨기기', subTitle: '워크플로우 세부 정보', }, chatColorTheme: '챗봇 색상 테마', chatColorThemeDesc: '챗봇의 색상 테마를 설정하세요', chatColorThemeInverted: '반전', - invalidHexMessage: '잘못된 16진수 값', - invalidPrivacyPolicy: '유효하지 않은 개인정보처리방침 링크입니다. http 또는 https로 시작하는 유효한 링크를 사용해 주세요', + invalidHexMessage: '잘못된 16 진수 값', + invalidPrivacyPolicy: '유효하지 않은 개인정보처리방침 링크입니다. http 또는 https 로 시작하는 유효한 링크를 사용해 주세요', more: { entry: '추가 설정 보기', copyright: '저작권', copyRightPlaceholder: '저작권자 또는 조직 이름을 입력하세요', privacyPolicy: '개인정보 처리방침', privacyPolicyPlaceholder: '개인정보 처리방침 링크를 입력하세요', - privacyPolicyTip: '방문자가 애플리케이션이 수집하는 데이터를 이해하고, Dify의 개인정보 처리방침을 참조할 수 있도록 합니다.', + privacyPolicyTip: '방문자가 애플리케이션이 수집하는 데이터를 이해하고, Dify 의 개인정보 처리방침을 참조할 수 있도록 합니다.', customDisclaimer: '사용자 지정 면책 조항', customDisclaimerPlaceholder: '사용자 지정 면책 조항 텍스트를 입력합니다.', customDisclaimerTip: '사용자 지정 고지 사항 텍스트는 클라이언트 쪽에 표시되어 응용 프로그램에 대한 추가 정보를 제공합니다', @@ -72,8 +72,8 @@ const translation = { sso: { label: 'SSO 인증', title: '웹앱 SSO', - tooltip: '관리자에게 문의하여 web app SSO를 사용하도록 설정합니다.', - description: '모든 사용자는 WebApp을 사용하기 전에 SSO로 로그인해야 합니다.', + tooltip: '관리자에게 문의하여 web app SSO 를 사용하도록 설정합니다.', + description: '모든 사용자는 WebApp 을 사용하기 전에 SSO 로 로그인해야 합니다.', }, modalTip: '클라이언트 쪽 웹앱 설정.', }, @@ -81,8 +81,8 @@ const translation = { entry: '임베드', title: '웹사이트에 임베드하기', explanation: '챗봇 앱을 웹사이트에 임베드하는 방법을 선택하세요.', - iframe: '웹사이트의 원하는 위치에 챗봇 앱을 추가하려면 이 iframe을 HTML 코드에 추가하세요.', - scripts: '웹사이트의 우측 하단에 챗봇 앱을 추가하려면 이 코드를 HTML에 추가하세요.', + iframe: '웹사이트의 원하는 위치에 챗봇 앱을 추가하려면 이 iframe 을 HTML 코드에 추가하세요.', + scripts: '웹사이트의 우측 하단에 챗봇 앱을 추가하려면 이 코드를 HTML 에 추가하세요.', chromePlugin: 'Dify Chatbot Chrome 확장 프로그램 설치', copied: '복사되었습니다', copy: '복사', @@ -98,18 +98,18 @@ const translation = { title: 'AI 웹앱 사용자화', explanation: '시나리오와 스타일 요구에 따라 웹앱의 프론트엔드를 사용자화할 수 있습니다.', way1: { - name: '클라이언트 코드를 포크하여 수정하고 Vercel에 배포하기 (권장)', + name: '클라이언트 코드를 포크하여 수정하고 Vercel 에 배포하기 (권장)', step1: '클라이언트 코드를 포크하여 수정합니다', step1Tip: '여기를 클릭하여 소스 코드를 GitHub 계정에 포크하고 코드를 수정하세요', step1Operation: 'Dify-WebClient', - step2: 'Vercel에 배포합니다', - step2Tip: '여기를 클릭하여 리포지토리를 Vercel에 임포트하고 배포하세요', + step2: 'Vercel 에 배포합니다', + step2Tip: '여기를 클릭하여 리포지토리를 Vercel 에 임포트하고 배포하세요', step2Operation: '리포지토리 임포트', step3: '환경 변수를 설정합니다', - step3Tip: 'Vercel에 다음 환경 변수를 추가하세요', + step3Tip: 'Vercel 에 다음 환경 변수를 추가하세요', }, way2: { - name: '클라이언트 측 코드를 작성하여 API를 호출하고 서버에 배포합니다', + name: '클라이언트 측 코드를 작성하여 API 를 호출하고 서버에 배포합니다', operation: '문서', }, }, @@ -140,7 +140,7 @@ const translation = { }, activeUsers: { title: '활성 사용자 수', - explanation: 'AI와의 Q&A에 참여하는 고유 사용자 수; 엔지니어링/디버깅 목적의 프롬프트는 제외됩니다.', + explanation: 'AI 와의 Q&A 에 참여하는 고유 사용자 수; 엔지니어링/디버깅 목적의 프롬프트는 제외됩니다.', }, tokenUsage: { title: '토큰 사용량', @@ -149,7 +149,7 @@ const translation = { }, avgSessionInteractions: { title: '평균 세션 상호작용 수', - explanation: '사용자와 AI의 연속적인 커뮤니케이션 수; 대화형 애플리케이션을 위한 것입니다.', + explanation: '사용자와 AI 의 연속적인 커뮤니케이션 수; 대화형 애플리케이션을 위한 것입니다.', }, avgUserInteractions: { title: '평균 사용자 상호작용 수', @@ -157,15 +157,15 @@ const translation = { }, userSatisfactionRate: { title: '사용자 만족도율', - explanation: '1,000개의 메시지 당 "좋아요" 수입니다. 이는 사용자가 매우 만족한 응답의 비율을 나타냅니다.', + explanation: '1,000 개의 메시지 당 "좋아요" 수입니다. 이는 사용자가 매우 만족한 응답의 비율을 나타냅니다.', }, avgResponseTime: { title: '평균 응답 시간', - explanation: 'AI가 처리/응답하는 시간(밀리초); 텍스트 기반 애플리케이션을 위한 것입니다.', + explanation: 'AI 가 처리/응답하는 시간 (밀리초); 텍스트 기반 애플리케이션을 위한 것입니다.', }, tps: { title: '토큰 출력 속도', - explanation: 'LLM의 성능을 측정합니다. 요청 시작부터 출력 완료까지의 LLM의 토큰 출력 속도를 계산합니다.', + explanation: 'LLM 의 성능을 측정합니다. 요청 시작부터 출력 완료까지의 LLM 의 토큰 출력 속도를 계산합니다.', }, }, } diff --git a/web/i18n/ko-KR/app.ts b/web/i18n/ko-KR/app.ts index d800968eaa..0ab08251fb 100644 --- a/web/i18n/ko-KR/app.ts +++ b/web/i18n/ko-KR/app.ts @@ -34,7 +34,7 @@ const translation = { workflowWarning: '현재 베타 버전입니다.', chatbotType: '챗봇 오케스트레이션 방식', basic: '기본', - basicTip: '초보자용. 나중에 Chatflow로 전환할 수 있습니다.', + basicTip: '초보자용. 나중에 Chatflow 로 전환할 수 있습니다.', basicFor: '초보자용', basicDescription: '기본 오케스트레이션은 내장된 프롬프트를 수정할 수 없고 간단한 설정을 사용하여 챗봇 앱을 오케스트레이션합니다. 초보자용입니다.', advanced: 'Chatflow', @@ -85,7 +85,7 @@ const translation = { noAppsFound: '앱을 찾을 수 없습니다.', foundResult: '{{개수}} 결과', completionUserDescription: '간단한 구성으로 텍스트 생성 작업을 위한 AI 도우미를 빠르게 구축합니다.', - chatbotUserDescription: '간단한 구성으로 LLM 기반 챗봇을 빠르게 구축할 수 있습니다. 나중에 Chatflow로 전환할 수 있습니다.', + chatbotUserDescription: '간단한 구성으로 LLM 기반 챗봇을 빠르게 구축할 수 있습니다. 나중에 Chatflow 로 전환할 수 있습니다.', workflowShortDescription: '지능형 자동화를 위한 에이전트 플로우', agentUserDescription: '작업 목표를 달성하기 위해 반복적인 추론과 자율적인 도구를 사용할 수 있는 지능형 에이전트입니다.', advancedUserDescription: '메모리 기능과 챗봇 인터페이스를 갖춘 워크플로우', @@ -117,7 +117,7 @@ const translation = { }, tracing: { title: '앱 성능 추적', - description: '제3자 LLMOps 제공업체 구성 및 앱 성능 추적.', + description: '제 3 자 LLMOps 제공업체 구성 및 앱 성능 추적.', config: '구성', collapse: '접기', expand: '펼치기', @@ -125,7 +125,7 @@ const translation = { disabled: '비활성화됨', disabledTip: '먼저 제공업체를 구성해 주세요', enabled: '서비스 중', - tracingDescription: 'LLM 호출, 컨텍스트, 프롬프트, HTTP 요청 등 앱 실행의 전체 컨텍스트를 제3자 추적 플랫폼에 캡처합니다.', + tracingDescription: 'LLM 호출, 컨텍스트, 프롬프트, HTTP 요청 등 앱 실행의 전체 컨텍스트를 제 3 자 추적 플랫폼에 캡처합니다.', configProviderTitle: { configured: '구성됨', notConfigured: '추적을 활성화하려면 제공업체를 구성하세요', @@ -153,27 +153,27 @@ const translation = { view: '보기', opik: { title: '오픽', - description: 'Opik은 LLM 애플리케이션을 평가, 테스트 및 모니터링하기 위한 오픈 소스 플랫폼입니다.', + description: 'Opik 은 LLM 애플리케이션을 평가, 테스트 및 모니터링하기 위한 오픈 소스 플랫폼입니다.', }, weave: { title: '직조하다', - description: 'Weave는 LLM 애플리케이션을 평가하고 테스트하며 모니터링하기 위한 오픈 소스 플랫폼입니다.', + description: 'Weave 는 LLM 애플리케이션을 평가하고 테스트하며 모니터링하기 위한 오픈 소스 플랫폼입니다.', }, }, answerIcon: { description: 'web app 아이콘을 사용하여 공유 응용 프로그램에서 바꿀🤖지 여부', title: 'web app 아이콘을 사용하여 🤖', - descriptionInExplore: 'Explore에서 web app 아이콘을 사용하여 바꿀🤖지 여부', + descriptionInExplore: 'Explore 에서 web app 아이콘을 사용하여 바꿀🤖지 여부', }, - importFromDSL: 'DSL에서 가져오기', + importFromDSL: 'DSL 에서 가져오기', importFromDSLFile: 'DSL 파일에서', - importFromDSLUrl: 'URL에서', + importFromDSLUrl: 'URL 에서', importFromDSLUrlPlaceholder: '여기에 DSL 링크 붙여 넣기', mermaid: { handDrawn: '손으로 그린', classic: '고전', }, - openInExplore: 'Explore에서 열기', + openInExplore: 'Explore 에서 열기', newAppFromTemplate: { sidebar: { Agent: '대리인', @@ -201,7 +201,7 @@ const translation = { notConfiguredTip: '구성이 아직 설정되지 않았습니다.', structured: '구조화된', configure: '설정하다', - moreFillTip: '최대 10단계 중첩을 표시합니다.', + moreFillTip: '최대 10 단계 중첩을 표시합니다.', modelNotSupportedTip: '현재 모델은 이 기능을 지원하지 않으며 자동으로 프롬프트 주입으로 다운그레이드됩니다.', structuredTip: '구조화된 출력은 모델이 제공한 JSON 스키마를 항상 준수하는 응답을 생성하도록 보장하는 기능입니다.', }, diff --git a/web/i18n/ko-KR/billing.ts b/web/i18n/ko-KR/billing.ts index dfb9f6abb2..87ccf27fe0 100644 --- a/web/i18n/ko-KR/billing.ts +++ b/web/i18n/ko-KR/billing.ts @@ -9,7 +9,7 @@ const translation = { buyPermissionDeniedTip: '구독하려면 엔터프라이즈 관리자에게 문의하세요', plansCommon: { title: '당신에게 맞는 요금제를 선택하세요', - yearlyTip: '연간 구독 시 2개월 무료!', + yearlyTip: '연간 구독 시 2 개월 무료!', mostPopular: '가장 인기 있는', planRange: { monthly: '월간', @@ -30,8 +30,8 @@ const translation = { teamMembers: '팀 멤버', buildApps: '앱 만들기', vectorSpace: '벡터 공간', - vectorSpaceBillingTooltip: '1MB당 약 120만 글자의 벡터화된 데이터를 저장할 수 있습니다 (OpenAI Embeddings을 기반으로 추정되며 모델에 따라 다릅니다).', - vectorSpaceTooltip: '벡터 공간은 LLM이 데이터를 이해하는 데 필요한 장기 기억 시스템입니다.', + vectorSpaceBillingTooltip: '1MB 당 약 120 만 글자의 벡터화된 데이터를 저장할 수 있습니다 (OpenAI Embeddings 을 기반으로 추정되며 모델에 따라 다릅니다).', + vectorSpaceTooltip: '벡터 공간은 LLM 이 데이터를 이해하는 데 필요한 장기 기억 시스템입니다.', documentProcessingPriority: '문서 처리 우선순위', documentProcessingPriorityTip: '더 높은 문서 처리 우선순위를 원하시면 요금제를 업그레이드하세요.', documentProcessingPriorityUpgrade: '더 높은 정확성과 빠른 속도로 데이터를 처리합니다.', @@ -74,7 +74,7 @@ const translation = { title: '주석 응답 쿼터', tooltip: '수동으로 편집 및 응답 주석 달기로 앱의 사용자 정의 가능한 고품질 질의응답 기능을 제공합니다 (채팅 앱에만 해당).', }, - ragAPIRequestTooltip: 'Dify의 지식베이스 처리 기능을 호출하는 API 호출 수를 나타냅니다.', + ragAPIRequestTooltip: 'Dify 의 지식베이스 처리 기능을 호출하는 API 호출 수를 나타냅니다.', receiptInfo: '팀 소유자 및 팀 관리자만 구독 및 청구 정보를 볼 수 있습니다', annotationQuota: 'Annotation Quota(주석 할당량)', documentsUploadQuota: '문서 업로드 할당량', @@ -84,7 +84,7 @@ const translation = { apiRateLimit: 'API 요금 한도', cloud: '클라우드 서비스', unlimitedApiRate: 'API 호출 속도 제한 없음', - freeTrialTip: '200회의 OpenAI 호출에 대한 무료 체험.', + freeTrialTip: '200 회의 OpenAI 호출에 대한 무료 체험.', annualBilling: '연간 청구', getStarted: '시작하기', apiRateLimitUnit: '{{count,number}}/일', @@ -94,15 +94,15 @@ const translation = { teamMember_other: '{{count,number}} 팀원', teamMember_one: '{{count,number}} 팀원', priceTip: '작업 공간당/', - apiRateLimitTooltip: 'Dify API를 통한 모든 요청에는 API 요금 한도가 적용되며, 여기에는 텍스트 생성, 채팅 대화, 워크플로 실행 및 문서 처리가 포함됩니다.', + apiRateLimitTooltip: 'Dify API 를 통한 모든 요청에는 API 요금 한도가 적용되며, 여기에는 텍스트 생성, 채팅 대화, 워크플로 실행 및 문서 처리가 포함됩니다.', documentsRequestQuota: '{{count,number}}/분 지식 요청 비율 제한', documentsTooltip: '지식 데이터 소스에서 가져올 수 있는 문서 수에 대한 쿼터.', - documentsRequestQuotaTooltip: '지식 기반 내에서 작업 공간이 분당 수행할 수 있는 총 작업 수를 지정합니다. 여기에는 데이터 세트 생성, 삭제, 업데이트, 문서 업로드, 수정, 보관 및 지식 기반 쿼리가 포함됩니다. 이 지표는 지식 기반 요청의 성능을 평가하는 데 사용됩니다. 예를 들어, 샌드박스 사용자가 1분 이내에 10회의 연속 히트 테스트를 수행하면, 해당 작업 공간은 다음 1분 동안 데이터 세트 생성, 삭제, 업데이트 및 문서 업로드 또는 수정과 같은 작업을 수행하는 것이 일시적으로 제한됩니다.', + documentsRequestQuotaTooltip: '지식 기반 내에서 작업 공간이 분당 수행할 수 있는 총 작업 수를 지정합니다. 여기에는 데이터 세트 생성, 삭제, 업데이트, 문서 업로드, 수정, 보관 및 지식 기반 쿼리가 포함됩니다. 이 지표는 지식 기반 요청의 성능을 평가하는 데 사용됩니다. 예를 들어, 샌드박스 사용자가 1 분 이내에 10 회의 연속 히트 테스트를 수행하면, 해당 작업 공간은 다음 1 분 동안 데이터 세트 생성, 삭제, 업데이트 및 문서 업로드 또는 수정과 같은 작업을 수행하는 것이 일시적으로 제한됩니다.', }, plans: { sandbox: { name: '샌드박스', - description: 'GPT 무료 체험 200회', + description: 'GPT 무료 체험 200 회', includesTitle: '포함된 항목:', for: '핵심 기능 무료 체험', }, diff --git a/web/i18n/ko-KR/common.ts b/web/i18n/ko-KR/common.ts index 4fa8ec74e4..c0d64e71e0 100644 --- a/web/i18n/ko-KR/common.ts +++ b/web/i18n/ko-KR/common.ts @@ -103,20 +103,20 @@ const translation = { model: { params: { temperature: '온도', - temperatureTip: '랜덤성을 제어합니다. 온도를 낮추면 더 랜덤한 결과물을 얻을 수 있습니다. 온도가 0에 가까워질수록 모델은 결정적이고 반복적으로 작동합니다.', - top_p: '상위P', - top_pTip: '뉴클리어스 샘플링에 의한 다양성 제어: 0.5는 모든 확률 가중 옵션의 절반을 고려함을 의미합니다.', + temperatureTip: '랜덤성을 제어합니다. 온도를 낮추면 더 랜덤한 결과물을 얻을 수 있습니다. 온도가 0 에 가까워질수록 모델은 결정적이고 반복적으로 작동합니다.', + top_p: '상위 P', + top_pTip: '뉴클리어스 샘플링에 의한 다양성 제어: 0.5 는 모든 확률 가중 옵션의 절반을 고려함을 의미합니다.', presence_penalty: '존재 페널티', presence_penaltyTip: '이전 텍스트에서 토큰이 나타나는지 여부에 따라 새로운 토큰에 얼마나 많은 페널티를 부여할지 제어합니다. 모델이 새로운 주제에 대해 말할 가능성이 높아집니다.', frequency_penalty: '빈도 페널티', frequency_penaltyTip: '이전 텍스트 내 토큰의 기존 빈도에 따라 새로운 토큰에 얼마나 많은 페널티를 부여할지 제어합니다. 모델이 같은 문구를 글자 그대로 반복할 가능성이 줄어듭니다.', max_tokens: '최대 토큰', max_tokensTip: - '응답의 최대 길이를 토큰 단위로 제한하는 데 사용됩니다. 큰 값은 프롬프트, 채팅 로그 및 남은 공간에 대한 제한을 가질 수 있습니다. 2/3 이하로 설정하는 것이 좋습니다. gpt-4-1106-preview, gpt-4-vision-preview의 최대 토큰 (입력 128k 출력 4k)보다 작게 설정하는 것이 좋습니다.', + '응답의 최대 길이를 토큰 단위로 제한하는 데 사용됩니다. 큰 값은 프롬프트, 채팅 로그 및 남은 공간에 대한 제한을 가질 수 있습니다. 2/3 이하로 설정하는 것이 좋습니다. gpt-4-1106-preview, gpt-4-vision-preview 의 최대 토큰 (입력 128k 출력 4k) 보다 작게 설정하는 것이 좋습니다.', maxTokenSettingTip: '최대 토큰 설정이 높아서 프롬프트, 쿼리 및 데이터 공간에 제한이 생길 수 있습니다. 현재 모델의 최대 토큰의 80% 이하로 설정해주세요.', - setToCurrentModelMaxTokenTip: '최대 토큰이 현재 모델의 최대 토큰의 80%로 업데이트되었습니다 {{maxToken}}.', + setToCurrentModelMaxTokenTip: '최대 토큰이 현재 모델의 최대 토큰의 80% 로 업데이트되었습니다 {{maxToken}}.', stop_sequences: '중단 시퀀스', - stop_sequencesTip: 'API가 진행 중인 토큰 생성을 중단하는 최대 4개의 시퀀스입니다. 반환된 텍스트에는 중단 시퀀스가 포함되지 않습니다.', + stop_sequencesTip: 'API 가 진행 중인 토큰 생성을 중단하는 최대 4 개의 시퀀스입니다. 반환된 텍스트에는 중단 시퀀스가 포함되지 않습니다.', stop_sequencesPlaceholder: '시퀀스를 입력하고 탭 키를 누르세요', }, tone: { @@ -201,7 +201,7 @@ const translation = { deletePlaceholder: '이메일을 입력해 주세요', sendVerificationButton: '인증 코드 보내기', verificationLabel: '인증 코드', - verificationPlaceholder: '6자리 코드를 붙여넣습니다.', + verificationPlaceholder: '6 자리 코드를 붙여넣습니다.', permanentlyDeleteButton: '계정 영구 삭제', feedbackTitle: '피드백', feedbackLabel: '계정을 삭제한 이유를 알려주시겠습니까?', @@ -234,7 +234,7 @@ const translation = { sendInvite: '초대 보내기', invitedAsRole: '{{role}} 사용자로 초대되었습니다', invitationSent: '초대가 전송되었습니다', - invitationSentTip: '초대가 전송되었으며, 그들은 Dify에 로그인하여 당신의 팀 데이터에 액세스할 수 있습니다.', + invitationSentTip: '초대가 전송되었으며, 그들은 Dify 에 로그인하여 당신의 팀 데이터에 액세스할 수 있습니다.', invitationLink: '초대 링크', failedInvitationEmails: '다음 사용자들은 성공적으로 초대되지 않았습니다', ok: '확인', @@ -271,7 +271,7 @@ const translation = { validatedError: '검증 실패:', validating: '키를 확인하는 중...', saveFailed: 'API 키 저장 실패', - apiKeyExceedBill: '이 API KEY에는 사용 가능한 할당량이 없습니다. 자세한 내용은', + apiKeyExceedBill: '이 API KEY 에는 사용 가능한 할당량이 없습니다. 자세한 내용은', addKey: '키 추가', comingSoon: '곧 출시됨', editKey: '편집', @@ -287,7 +287,7 @@ const translation = { openaiHosted: '호스팅된 OpenAI', onTrial: '트라이얼 중', exhausted: '할당량이 다 사용되었습니다', - desc: 'Dify가 제공하는 OpenAI 호스팅 서비스를 사용하면 GPT-3.5와 같은 모델을 사용할 수 있습니다. 트라이얼 할당량이 다 사용되기 전에 다른 모델 제공자를 설정해야 합니다.', + desc: 'Dify 가 제공하는 OpenAI 호스팅 서비스를 사용하면 GPT-3.5 와 같은 모델을 사용할 수 있습니다. 트라이얼 할당량이 다 사용되기 전에 다른 모델 제공자를 설정해야 합니다.', callTimes: '호출 횟수', usedUp: '트라이얼 할당량이 다 사용되었습니다. 다른 모델 제공자를 추가하세요.', useYourModel: '현재 사용자 정의 모델 제공자를 사용 중입니다.', @@ -308,10 +308,10 @@ const translation = { using: '임베드 기능을 사용 중입니다', enableTip: 'Anthropic 모델을 활성화하려면 먼저 OpenAI 또는 Azure OpenAI 서비스에 바인딩해야 합니다.', notEnabled: '비활성화됨', - keyFrom: 'Anthropic에서 API 키를 받으세요', + keyFrom: 'Anthropic 에서 API 키를 받으세요', }, encrypted: { - front: 'API KEY는', + front: 'API KEY 는', back: '기술을 사용하여 암호화 및 저장됩니다.', }, }, @@ -366,7 +366,7 @@ const translation = { tip: '지불된 할당량에 우선순위가 부여됩니다. 평가판 할당량은 유료 할당량이 소진된 후 사용됩니다.', }, item: { - deleteDesc: '{{modelName}}은(는) 시스템 추론 모델로 사용 중입니다. 제거 후 일부 기능을 사용할 수 없습니다. 확인하시겠습니까?', + deleteDesc: '{{modelName}}은 (는) 시스템 추론 모델로 사용 중입니다. 제거 후 일부 기능을 사용할 수 없습니다. 확인하시겠습니까?', freeQuota: '무료 할당량', }, addApiKey: 'API 키 추가', @@ -401,7 +401,7 @@ const translation = { apiKey: 'API 키', defaultConfig: '기본 구성', providerManaged: '제공자 관리', - loadBalancing: '부하 분산Load balancing', + loadBalancing: '부하 분산 Load balancing', addConfig: '구성 추가', apiKeyStatusNormal: 'APIKey 상태는 정상입니다.', configLoadBalancing: 'Config 로드 밸런싱', @@ -411,8 +411,8 @@ const translation = { loadBalancingDescription: '여러 자격 증명 세트로 부담을 줄입니다.', upgradeForLoadBalancing: '로드 밸런싱을 사용하도록 계획을 업그레이드합니다.', apiKeyRateLimit: '속도 제한에 도달했으며, {{seconds}}s 후에 사용할 수 있습니다.', - loadBalancingInfo: '기본적으로 부하 분산은 라운드 로빈 전략을 사용합니다. 속도 제한이 트리거되면 1분의 휴지 기간이 적용됩니다.', - loadBalancingLeastKeyWarning: '로드 밸런싱을 사용하려면 최소 2개의 키를 사용하도록 설정해야 합니다.', + loadBalancingInfo: '기본적으로 부하 분산은 라운드 로빈 전략을 사용합니다. 속도 제한이 트리거되면 1 분의 휴지 기간이 적용됩니다.', + loadBalancingLeastKeyWarning: '로드 밸런싱을 사용하려면 최소 2 개의 키를 사용하도록 설정해야 합니다.', providerManagedDescription: '모델 공급자가 제공하는 단일 자격 증명 집합을 사용합니다.', installProvider: '모델 공급자 설치', discoverMore: '더 알아보기', @@ -484,7 +484,7 @@ const translation = { apiKey: { title: 'API 키', placeholder: 'API 키를 입력하세요', - lengthError: 'API 키는 5자 미만이어야 합니다', + lengthError: 'API 키는 5 자 미만이어야 합니다', }, }, type: '유형', @@ -604,7 +604,7 @@ const translation = { uploadFromComputer: '컴퓨터에서 업로드', uploadFromComputerReadError: '이미지 읽기 실패. 다시 시도하세요.', uploadFromComputerUploadError: '이미지 업로드 실패. 다시 업로드하세요.', - uploadFromComputerLimit: '업로드 이미지 크기는 {{size}} MB를 초과할 수 없습니다', + uploadFromComputerLimit: '업로드 이미지 크기는 {{size}} MB 를 초과할 수 없습니다', pasteImageLink: '이미지 링크 붙여넣기', pasteImageLinkInputPlaceholder: '여기에 이미지 링크를 붙여넣으세요', pasteImageLinkInvalid: '유효하지 않은 이미지 링크', @@ -626,7 +626,7 @@ const translation = { failed: '태그 생성에 실패했습니다', }, errorMsg: { - urlError: 'URL은 http:// 또는 https:// 로 시작해야 합니다.', + urlError: 'URL 은 http:// 또는 https:// 로 시작해야 합니다.', fieldRequired: '{{field}}는 필수입니다.', }, fileUploader: { @@ -662,7 +662,7 @@ const translation = { sandboxUpgradeTooltip: '전문가 또는 팀 플랜에서만 사용할 수 있습니다.', }, imageInput: { - supportedFormats: 'PNG, JPG, JPEG, WEBP 및 GIF를 지원합니다.', + supportedFormats: 'PNG, JPG, JPEG, WEBP 및 GIF 를 지원합니다.', browse: '브라우즈', dropImageHere: '여기에 이미지를 드롭하거나', }, diff --git a/web/i18n/ko-KR/custom.ts b/web/i18n/ko-KR/custom.ts index f5bb34008d..9b70e7326a 100644 --- a/web/i18n/ko-KR/custom.ts +++ b/web/i18n/ko-KR/custom.ts @@ -10,11 +10,11 @@ const translation = { title: 'web app 브랜드 사용자 정의', removeBrand: 'Powered by Dify 삭제', changeLogo: 'Powered by 브랜드 이미지 변경', - changeLogoTip: '최소 크기 40x40px의 SVG 또는 PNG 형식', + changeLogoTip: '최소 크기 40x40px 의 SVG 또는 PNG 형식', }, app: { title: '앱 헤더 브랜드 사용자 정의', - changeLogoTip: '최소 크기 80x80px의 SVG 또는 PNG 형식', + changeLogoTip: '최소 크기 80x80px 의 SVG 또는 PNG 형식', }, upload: '업로드', uploading: '업로드 중', diff --git a/web/i18n/ko-KR/dataset-creation.ts b/web/i18n/ko-KR/dataset-creation.ts index 4b5ee3f03f..33f6e332a0 100644 --- a/web/i18n/ko-KR/dataset-creation.ts +++ b/web/i18n/ko-KR/dataset-creation.ts @@ -24,19 +24,19 @@ const translation = { title: '텍스트 파일 업로드', button: '파일이나 폴더를 끌어서 놓기', browse: '찾아보기', - tip: '{{supportTypes}}을(를) 지원합니다. 파일당 최대 크기는 {{size}}MB입니다.', + tip: '{{supportTypes}}을 (를) 지원합니다. 파일당 최대 크기는 {{size}}MB 입니다.', validation: { typeError: '지원되지 않는 파일 유형입니다', - size: '파일 크기가 너무 큽니다. 최대 크기는 {{size}}MB입니다', + size: '파일 크기가 너무 큽니다. 최대 크기는 {{size}}MB 입니다', count: '여러 파일은 지원되지 않습니다', - filesNumber: '일괄 업로드 제한({{filesNumber}}개)에 도달했습니다.', + filesNumber: '일괄 업로드 제한 ({{filesNumber}}개) 에 도달했습니다.', }, cancel: '취소', change: '변경', failed: '업로드에 실패했습니다', }, - notionSyncTitle: 'Notion에 연결되지 않았습니다', - notionSyncTip: 'Notion과 동기화하려면 먼저 Notion에 연결해야 합니다.', + notionSyncTitle: 'Notion 에 연결되지 않았습니다', + notionSyncTip: 'Notion 과 동기화하려면 먼저 Notion 에 연결해야 합니다.', connect: '연결하기', button: '다음', emptyDatasetCreation: '비어있는 지식 생성', @@ -46,7 +46,7 @@ const translation = { input: '지식 이름', placeholder: '입력하세요', nameNotEmpty: '이름은 비워둘 수 없습니다', - nameLengthInvalid: '이름은 1~40자여야 합니다', + nameLengthInvalid: '이름은 1~40 자여야 합니다', cancelButton: '취소', confirmButton: '생성', failed: '생성에 실패했습니다', @@ -62,8 +62,8 @@ const translation = { excludePaths: '경로 제외', preview: '미리 보기', run: '달리다', - fireCrawlNotConfigured: 'Firecrawl이 구성되지 않았습니다.', - firecrawlTitle: 'Firecrawl로 🔥웹 콘텐츠 추출', + fireCrawlNotConfigured: 'Firecrawl 이 구성되지 않았습니다.', + firecrawlTitle: 'Firecrawl 로 🔥웹 콘텐츠 추출', configure: '구성', resetAll: '모두 재설정', crawlSubPage: '하위 페이지 크롤링', @@ -71,24 +71,24 @@ const translation = { scrapTimeInfo: '{{time}}s 내에 총 {{total}} 페이지를 스크랩했습니다.', unknownError: '알 수 없는 오류', totalPageScraped: '스크랩한 총 페이지 수:', - fireCrawlNotConfiguredDescription: 'API 키로 Firecrawl을 구성하여 사용합니다.', - extractOnlyMainContent: '기본 콘텐츠만 추출합니다(머리글, 탐색, 바닥글 등 없음).', - maxDepthTooltip: '입력한 URL을 기준으로 크롤링할 최대 수준입니다. 깊이 0은 입력 된 url의 페이지를 긁어 내고, 깊이 1은 url과 enteredURL + one / 이후의 모든 것을 긁어 모으는 식입니다.', + fireCrawlNotConfiguredDescription: 'API 키로 Firecrawl 을 구성하여 사용합니다.', + extractOnlyMainContent: '기본 콘텐츠만 추출합니다 (머리글, 탐색, 바닥글 등 없음).', + maxDepthTooltip: '입력한 URL 을 기준으로 크롤링할 최대 수준입니다. 깊이 0 은 입력 된 url 의 페이지를 긁어 내고, 깊이 1 은 url 과 enteredURL + one / 이후의 모든 것을 긁어 모으는 식입니다.', chooseProvider: '제공자 선택', jinaReaderDocLink: 'https://jina.ai/reader', useSitemap: '사이트맵 사용', - jinaReaderNotConfiguredDescription: '액세스를 위해 무료 API 키를 입력하여 Jina Reader를 설정합니다.', - jinaReaderDoc: 'Jina Reader에 대해 자세히 알아보기', - jinaReaderTitle: '전체 사이트를 Markdown으로 변환', - jinaReaderNotConfigured: 'Jina Reader가 구성되지 않았습니다.', - useSitemapTooltip: '사이트맵을 따라 사이트를 크롤링합니다. 그렇지 않은 경우 Jina Reader는 페이지 관련성에 따라 반복적으로 크롤링하여 더 적지만 더 높은 품질의 페이지를 생성합니다.', + jinaReaderNotConfiguredDescription: '액세스를 위해 무료 API 키를 입력하여 Jina Reader 를 설정합니다.', + jinaReaderDoc: 'Jina Reader 에 대해 자세히 알아보기', + jinaReaderTitle: '전체 사이트를 Markdown 으로 변환', + jinaReaderNotConfigured: 'Jina Reader 가 구성되지 않았습니다.', + useSitemapTooltip: '사이트맵을 따라 사이트를 크롤링합니다. 그렇지 않은 경우 Jina Reader 는 페이지 관련성에 따라 반복적으로 크롤링하여 더 적지만 더 높은 품질의 페이지를 생성합니다.', watercrawlDoc: '워터크롤 문서', - waterCrawlNotConfiguredDescription: 'API 키로 Watercrawl을 구성하여 사용하십시오.', - watercrawlTitle: 'Watercrawl로 웹 콘텐츠 추출하기', + waterCrawlNotConfiguredDescription: 'API 키로 Watercrawl 을 구성하여 사용하십시오.', + watercrawlTitle: 'Watercrawl 로 웹 콘텐츠 추출하기', configureFirecrawl: '파이어크롤 구성하기', watercrawlDocLink: '웹사이트에서 동기화하기', configureJinaReader: '지나 리더 설정하기', - waterCrawlNotConfigured: 'Watercrawl이 설정되어 있지 않습니다.', + waterCrawlNotConfigured: 'Watercrawl 이 설정되어 있지 않습니다.', configureWatercrawl: '워터크롤 구성하기', }, cancel: '취소', @@ -100,15 +100,15 @@ const translation = { custom: '사용자 설정', customDescription: '청크 규칙, 청크 길이, 전처리 규칙 등을 사용자 정의합니다.', separator: '세그먼트 식별자', - separatorPlaceholder: '예: 줄바꿈(\\\\n) 또는 특수 구분자(예: "***")', + separatorPlaceholder: '예: 줄바꿈 (\\\\n) 또는 특수 구분자 (예: "***")', maxLength: '최대 청크 길이', overlap: '청크 중첩', - overlapTip: '청크 중첩을 설정하여 그 사이의 의미적 연관성을 유지하고 검색 효과를 향상시킬 수 있습니다. 최대 청크 크기의 10%~25%로 설정하는 것이 좋습니다.', + overlapTip: '청크 중첩을 설정하여 그 사이의 의미적 연관성을 유지하고 검색 효과를 향상시킬 수 있습니다. 최대 청크 크기의 10%~25% 로 설정하는 것이 좋습니다.', overlapCheck: '청크 중첩은 최대 청크 길이를 초과할 수 없습니다', rules: '텍스트 전처리 규칙', removeExtraSpaces: '연속된 공백, 줄바꿈, 탭을 대체합니다', - removeUrlEmails: '모든 URL과 이메일 주소를 제거합니다', - removeStopwords: '일반적인 불용어(예: "a", "an", "the" 등)를 제거합니다', + removeUrlEmails: '모든 URL 과 이메일 주소를 제거합니다', + removeStopwords: '일반적인 불용어 (예: "a", "an", "the" 등) 를 제거합니다', preview: '미리보기', reset: '초기화', indexMode: '인덱스 모드', @@ -142,7 +142,7 @@ const translation = { sideTipP4: '적절한 청크와 클리닝은 모델의 성능을 향상시키고 정확하고 가치 있는 결과를 제공합니다.', previewTitle: '미리보기', previewTitleButton: '미리보기', - previewButton: '질문-답변 형식으로 전환', + previewButton: '질문 - 답변 형식으로 전환', previewSwitchTipStart: '현재 청크 미리보기는 텍스트 형식입니다. 질문과 답변 형식 미리보기로 전환하면', previewSwitchTipEnd: ' 추가 토큰이 소비됩니다', characters: '문자', @@ -151,25 +151,25 @@ const translation = { datasetSettingLink: '지식 설정', webpageUnit: '페이지', websiteSource: '웹 사이트 전처리', - separatorTip: '구분 기호는 텍스트를 구분하는 데 사용되는 문자입니다. \\n\\n 및 \\n은 단락과 줄을 구분하는 데 일반적으로 사용되는 구분 기호입니다. 쉼표(\\n\\n,\\n)와 함께 사용하면 최대 청크 길이를 초과할 경우 단락이 줄로 분할됩니다. 직접 정의한 특수 구분 기호(예: ***)를 사용할 수도 있습니다.', + separatorTip: '구분 기호는 텍스트를 구분하는 데 사용되는 문자입니다. \\n\\n 및 \\n은 단락과 줄을 구분하는 데 일반적으로 사용되는 구분 기호입니다. 쉼표 (\\n\\n,\\n) 와 함께 사용하면 최대 청크 길이를 초과할 경우 단락이 줄로 분할됩니다. 직접 정의한 특수 구분 기호 (예: ***) 를 사용할 수도 있습니다.', maxLengthCheck: '최대 청크 길이는 {{limit}} 미만이어야 합니다.', childChunkForRetrieval: '검색을 위한 자식 청크', qaSwitchHighQualityTipContent: '현재 고품질 인덱스 방법만 Q&A 형식 청크를 지원합니다. 고화질 모드로 전환하시겠습니까?', previewChunkTip: '왼쪽의 \'Preview Chunk\' 버튼을 클릭하여 프리뷰를 로드합니다', general: '일반', fullDoc: '전체 문서', - previewChunk: '프리뷰 청크(Preview Chunk)', + previewChunk: '프리뷰 청크 (Preview Chunk)', parentChunkForContext: '컨텍스트에 대한 Parent-chunk', parentChildDelimiterTip: '구분 기호는 텍스트를 구분하는 데 사용되는 문자입니다. \\n\\n은 원본 문서를 큰 부모 청크로 분할하는 데 권장됩니다. 직접 정의한 특수 구분 기호를 사용할 수도 있습니다.', paragraph: '단락', - parentChild: '부모-자식', + parentChild: '부모 - 자식', useQALanguage: 'Q&A 형식을 사용하는 청크', highQualityTip: '고품질 모드에서 삽입을 마치면 경제적 모드로 되돌릴 수 없습니다.', notAvailableForQA: 'Q&A 인덱스에는 사용할 수 없습니다.', qaSwitchHighQualityTipTitle: 'Q&A 형식에는 고품질 인덱싱 방법이 필요합니다.', - notAvailableForParentChild: '부모-자식 인덱스에는 사용할 수 없습니다.', + notAvailableForParentChild: '부모 - 자식 인덱스에는 사용할 수 없습니다.', previewChunkCount: '{{개수}} 추정된 청크', - parentChildTip: '부모-자식 모드를 사용할 때 자식 청크는 검색에 사용되고 부모 청크는 컨텍스트로 회수에 사용됩니다.', + parentChildTip: '부모 - 자식 모드를 사용할 때 자식 청크는 검색에 사용되고 부모 청크는 컨텍스트로 회수에 사용됩니다.', generalTip: '일반적인 텍스트 청크 모드에서는 검색된 청크와 회수된 청크가 동일합니다.', fullDocTip: '전체 문서가 상위 청크로 사용되며 직접 검색됩니다. 성능상의 이유로 10000 토큰을 초과하는 텍스트는 자동으로 잘립니다.', parentChildChunkDelimiterTip: '구분 기호는 텍스트를 구분하는 데 사용되는 문자입니다. \\n 은 부모 청크를 작은 자식 청크로 분할하는 데 권장됩니다. 직접 정의한 특수 구분 기호를 사용할 수도 있습니다.', @@ -207,12 +207,12 @@ const translation = { otherDataSource: { learnMore: '더 알아보세요', title: '다른 데이터 소스에 연결하시겠습니까?', - description: '현재 Dify의 기술 자료에는 제한된 데이터 소스만 있습니다. Dify 기술 자료에 데이터 소스를 제공하는 것은 모든 사용자를 위해 플랫폼의 유연성과 기능을 향상시키는 데 도움이 되는 환상적인 방법입니다. 기여 가이드를 통해 쉽게 시작할 수 있습니다. 자세한 내용은 아래 링크를 클릭하십시오.', + description: '현재 Dify 의 기술 자료에는 제한된 데이터 소스만 있습니다. Dify 기술 자료에 데이터 소스를 제공하는 것은 모든 사용자를 위해 플랫폼의 유연성과 기능을 향상시키는 데 도움이 되는 환상적인 방법입니다. 기여 가이드를 통해 쉽게 시작할 수 있습니다. 자세한 내용은 아래 링크를 클릭하십시오.', }, watercrawl: { - getApiKeyLinkText: 'watercrawl.dev에서 API 키를 얻으세요.', + getApiKeyLinkText: 'watercrawl.dev 에서 API 키를 얻으세요.', configWatercrawl: '워터크롤 구성하기', - apiKeyPlaceholder: 'watercrawl.dev의 API 키', + apiKeyPlaceholder: 'watercrawl.dev 의 API 키', }, } diff --git a/web/i18n/ko-KR/dataset-documents.ts b/web/i18n/ko-KR/dataset-documents.ts index a00d3a7c25..a379318959 100644 --- a/web/i18n/ko-KR/dataset-documents.ts +++ b/web/i18n/ko-KR/dataset-documents.ts @@ -1,7 +1,7 @@ const translation = { list: { title: '문서', - desc: '지식의 모든 파일이 여기에 표시되며, 전체 지식이 Dify의 인용문이나 챗 플러그인을 통해 링크되거나 색인화될 수 있습니다.', + desc: '지식의 모든 파일이 여기에 표시되며, 전체 지식이 Dify 의 인용문이나 챗 플러그인을 통해 링크되거나 색인화될 수 있습니다.', addFile: '파일 추가', addPages: '페이지 추가', table: { @@ -49,10 +49,10 @@ const translation = { empty: { title: '아직 문서가 없습니다', upload: { - tip: '파일을 업로드하거나 웹 사이트에서 동기화하거나 Notion이나 GitHub 같은 웹 앱에서 동기화할 수 있습니다.', + tip: '파일을 업로드하거나 웹 사이트에서 동기화하거나 Notion 이나 GitHub 같은 웹 앱에서 동기화할 수 있습니다.', }, sync: { - tip: 'Dify는 정기적으로 Notion에서 파일을 다운로드하고 처리합니다.', + tip: 'Dify 는 정기적으로 Notion 에서 파일을 다운로드하고 처리합니다.', }, }, delete: { @@ -82,8 +82,8 @@ const translation = { }, metadata: { title: '메타데이터', - desc: '문서 메타데이터에 레이블을 붙여 AI가 신속하게 접근할 수 있고 사용자에게 출처가 공개됩니다.', - dateTimeFormat: 'YYYY년 M월 D일 hh:mm A', + desc: '문서 메타데이터에 레이블을 붙여 AI 가 신속하게 접근할 수 있고 사용자에게 출처가 공개됩니다.', + dateTimeFormat: 'YYYY 년 M 월 D 일 hh:mm A', docTypeSelectTitle: '문서 유형을 선택하세요', docTypeChangeTitle: '문서 유형 변경', docTypeSelectWarning: '문서 유형을 변경하면 현재 입력된 메타데이터가 유지되지 않습니다.', @@ -94,8 +94,8 @@ const translation = { }, source: { upload_file: '파일 업로드', - notion: 'Notion에서 동기화', - github: 'GitHub에서 동기화', + notion: 'Notion 에서 동기화', + github: 'GitHub 에서 동기화', }, type: { book: '도서', @@ -106,8 +106,8 @@ const translation = { businessDocument: '비즈니스 문서', IMChat: 'IM 채팅', wikipediaEntry: '위키피디아 항목', - notion: 'Notion에서 동기화', - github: 'GitHub에서 동기화', + notion: 'Notion 에서 동기화', + github: 'GitHub 에서 동기화', technicalParameters: '기술적 매개변수', }, field: { @@ -332,13 +332,13 @@ const translation = { childMaxTokens: '아이', parentMaxTokens: '부모', pause: '일시 중지', - hierarchical: '부모-자식', + hierarchical: '부모 - 자식', }, segment: { paragraphs: '단락', keywords: '키워드', addKeyWord: '키워드 추가', - keywordError: '키워드 최대 길이는 20자입니다', + keywordError: '키워드 최대 길이는 20 자입니다', characters: '문자', hitCount: '검색 횟수', vectorHash: '벡터 해시: ', @@ -351,41 +351,41 @@ const translation = { newTextSegment: '새로운 텍스트 세그먼트', newQaSegment: '새로운 Q&A 세그먼트', delete: '이 청크를 삭제하시겠습니까?', - parentChunks_one: '부모 청크(PARENT CHUNK)', + parentChunks_one: '부모 청크 (PARENT CHUNK)', newChunk: '새 청크', - addChildChunk: '자손 청크 추가(Add Child Chunk)', - editChildChunk: '자손 청크 편집(Edit Child Chunk)', - chunkDetail: '청크 디테일(Chunk Detail)', - editChunk: '청크 편집(Edit Chunk)', + addChildChunk: '자손 청크 추가 (Add Child Chunk)', + editChildChunk: '자손 청크 편집 (Edit Child Chunk)', + chunkDetail: '청크 디테일 (Chunk Detail)', + editChunk: '청크 편집 (Edit Chunk)', regeneratingTitle: '자식 청크 재생성', - newChildChunk: '새 자손 청크(New Child Chunk)', - childChunkAdded: '자식 청크 1개 추가됨', + newChildChunk: '새 자손 청크 (New Child Chunk)', + childChunkAdded: '자식 청크 1 개 추가됨', chunk: '덩어리', searchResults_zero: '결과', empty: '청크를 찾을 수 없습니다.', - editParentChunk: '부모 청크 편집(Edit Parent Chunk)', + editParentChunk: '부모 청크 편집 (Edit Parent Chunk)', chunks_one: '덩어리', regenerationSuccessMessage: '이 창을 닫을 수 있습니다.', - childChunks_one: '자식 청크(CHILD CHUNK)', + childChunks_one: '자식 청크 (CHILD CHUNK)', regenerationSuccessTitle: '재생이 완료되었습니다.', editedAt: '편집 위치', addAnother: '다른 항목 추가', - chunkAdded: '청크 1개 추가됨', + chunkAdded: '청크 1 개 추가됨', searchResults_one: '결과', searchResults_other: '결과', regenerationConfirmMessage: '자식 청크를 다시 생성하면 편집된 청크와 새로 추가된 청크를 포함하여 현재 자식 청크를 덮어씁니다. 재생성은 취소할 수 없습니다.', regenerationConfirmTitle: '자식 청크를 다시 생성하시겠습니까?', clearFilter: '필터 지우기', characters_one: '문자', - parentChunk: '부모-청크', + parentChunk: '부모 - 청크', expandChunks: '청크 확장', collapseChunks: '청크 축소', - parentChunks_other: '부모 청크(PARENT CHUNKS)', + parentChunks_other: '부모 청크 (PARENT CHUNKS)', childChunk: '자식 청크', childChunks_other: '자식 청크', chunks_other: '청크', edited: '편집', - addChunk: '청크 추가(Add Chunk)', + addChunk: '청크 추가 (Add Chunk)', characters_other: '문자', regeneratingMessage: '시간이 걸릴 수 있으니 잠시만 기다려 주십시오...', }, diff --git a/web/i18n/ko-KR/dataset-hit-testing.ts b/web/i18n/ko-KR/dataset-hit-testing.ts index a5329fbdb5..17ab7db08a 100644 --- a/web/i18n/ko-KR/dataset-hit-testing.ts +++ b/web/i18n/ko-KR/dataset-hit-testing.ts @@ -13,7 +13,7 @@ const translation = { input: { title: '소스 텍스트', placeholder: '텍스트를 입력하세요. 간결한 설명문이 좋습니다.', - countWarning: '최대 200자까지 입력할 수 있습니다.', + countWarning: '최대 200 자까지 입력할 수 있습니다.', indexWarning: '고품질 지식만.', testing: '테스트 중', }, @@ -29,7 +29,7 @@ const translation = { records: '레코드', hitChunks: '{{num}}개의 자식 청크를 히트했습니다.', keyword: '키워드', - chunkDetail: '청크 디테일(Chunk Detail)', + chunkDetail: '청크 디테일 (Chunk Detail)', } export default translation diff --git a/web/i18n/ko-KR/dataset-settings.ts b/web/i18n/ko-KR/dataset-settings.ts index b008e37ccd..272cd4b9f9 100644 --- a/web/i18n/ko-KR/dataset-settings.ts +++ b/web/i18n/ko-KR/dataset-settings.ts @@ -7,7 +7,7 @@ const translation = { nameError: '이름은 비워둘 수 없습니다', desc: '지식 설명', descInfo: '지식 내용을 개괄하는 명확한 텍스트 설명을 작성하세요. 이 설명은 여러 지식 중에서 선택하는 기준으로 사용됩니다.', - descPlaceholder: '이 지식에 포함된 내용을 설명하세요. 자세한 설명은 AI가 지식 내용에 빠르게 접근할 수 있도록 합니다. 비어 있으면 Dify가 기본 검색 전략을 사용합니다.', + descPlaceholder: '이 지식에 포함된 내용을 설명하세요. 자세한 설명은 AI 가 지식 내용에 빠르게 접근할 수 있도록 합니다. 비어 있으면 Dify 가 기본 검색 전략을 사용합니다.', descWrite: '좋은 지식 설명 작성 방법 배우기', permissions: '권한', permissionsOnlyMe: '나만', @@ -34,7 +34,7 @@ const translation = { externalKnowledgeID: '외부 지식 ID', retrievalSettings: '검색 설정', upgradeHighQualityTip: '고품질 모드로 업그레이드한 후에는 경제적 모드로 되돌릴 수 없습니다.', - indexMethodChangeToEconomyDisabledTip: 'HQ에서 ECO로 다운그레이드할 수 없습니다.', + indexMethodChangeToEconomyDisabledTip: 'HQ 에서 ECO 로 다운그레이드할 수 없습니다.', helpText: '좋은 데이터 세트 설명을 작성하는 방법을 알아보세요.', searchModel: '모델 검색', }, diff --git a/web/i18n/ko-KR/dataset.ts b/web/i18n/ko-KR/dataset.ts index a95e039932..3eb4634194 100644 --- a/web/i18n/ko-KR/dataset.ts +++ b/web/i18n/ko-KR/dataset.ts @@ -67,17 +67,17 @@ const translation = { semantic: '의미론적', keyword: '키워드', }, - nTo1RetrievalLegacy: 'N-대-1 검색은 9월부터 공식적으로 더 이상 사용되지 않습니다. 더 나은 결과를 얻으려면 최신 다중 경로 검색을 사용하는 것이 좋습니다.', + nTo1RetrievalLegacy: 'N-대 -1 검색은 9 월부터 공식적으로 더 이상 사용되지 않습니다. 더 나은 결과를 얻으려면 최신 다중 경로 검색을 사용하는 것이 좋습니다.', nTo1RetrievalLegacyLink: '자세히 알아보기', - nTo1RetrievalLegacyLinkText: 'N-대-1 검색은 9월에 공식적으로 더 이상 사용되지 않습니다.', + nTo1RetrievalLegacyLinkText: 'N-대 -1 검색은 9 월에 공식적으로 더 이상 사용되지 않습니다.', defaultRetrievalTip: '다중 경로 검색이 기본적으로 사용됩니다. 지식은 여러 기술 자료에서 검색된 다음 순위가 다시 매겨집니다.', editExternalAPIConfirmWarningContent: { - front: '이 외부 지식 API는 다음에 연결됩니다.', + front: '이 외부 지식 API 는 다음에 연결됩니다.', end: '외부 지식, 그리고 이 수정 사항은 그들 모두에게 적용될 것입니다. 이 변경 사항을 저장하시겠습니까?', }, editExternalAPIFormWarning: { end: '외부 지식', - front: '이 외부 API는 다음에 연결됩니다.', + front: '이 외부 API 는 다음에 연결됩니다.', }, deleteExternalAPIConfirmWarningContent: { title: { @@ -85,25 +85,25 @@ const translation = { end: '?', }, content: { - front: '이 외부 지식 API는 다음에 연결됩니다.', - end: '외부 지식. 이 API를 삭제하면 모두 무효화됩니다. 이 API를 삭제하시겠습니까?', + front: '이 외부 지식 API 는 다음에 연결됩니다.', + end: '외부 지식. 이 API 를 삭제하면 모두 무효화됩니다. 이 API 를 삭제하시겠습니까?', }, - noConnectionContent: '이 API를 삭제하시겠습니까?', + noConnectionContent: '이 API 를 삭제하시겠습니까?', }, selectExternalKnowledgeAPI: { placeholder: '외부 지식 API 선택', }, connectDatasetIntro: { content: { - link: '외부 API를 만드는 방법 알아보기', - end: '. 그런 다음 해당 기술 ID를 찾아 왼쪽 양식에 입력합니다. 모든 정보가 올바르면 연결 단추를 클릭한 후 기술 자료의 검색 테스트로 자동으로 이동합니다.', - front: '외부 기술 자료에 연결하려면 먼저 외부 API를 만들어야 합니다. 주의 깊게 읽고 참조하십시오.', + link: '외부 API 를 만드는 방법 알아보기', + end: '. 그런 다음 해당 기술 ID 를 찾아 왼쪽 양식에 입력합니다. 모든 정보가 올바르면 연결 단추를 클릭한 후 기술 자료의 검색 테스트로 자동으로 이동합니다.', + front: '외부 기술 자료에 연결하려면 먼저 외부 API 를 만들어야 합니다. 주의 깊게 읽고 참조하십시오.', }, learnMore: '더 알아보세요', title: '외부 기술 자료에 연결하는 방법', }, connectHelper: { - helper1: 'API 및 기술 자료 ID를 통해 외부 기술 자료에 연결합니다. 현재,', + helper1: 'API 및 기술 자료 ID 를 통해 외부 기술 자료에 연결합니다. 현재,', helper4: '도움말 문서 읽기', helper2: '검색 기능만 지원됩니다', helper5: '이 기능을 사용하기 전에 주의하십시오.', @@ -134,19 +134,19 @@ const translation = { externalTag: '외부', editExternalAPIFormTitle: '외부 지식 API 편집', externalKnowledgeNamePlaceholder: '기술 자료의 이름을 입력하십시오.', - externalAPIPanelDocumentation: '외부 지식 API를 만드는 방법 알아보기', + externalAPIPanelDocumentation: '외부 지식 API 를 만드는 방법 알아보기', createNewExternalAPI: '새 외부 지식 API 만들기', mixtureInternalAndExternalTip: '리랭크 모델은 내부 및 외부 지식의 혼합에 필요합니다.', connectDataset: '외부 기술 자료에 연결', learnHowToWriteGoodKnowledgeDescription: '적절한 지식 설명을 작성하는 방법 알아보기', - externalKnowledgeDescriptionPlaceholder: '이 기술 자료의 내용 설명(선택 사항)', + externalKnowledgeDescriptionPlaceholder: '이 기술 자료의 내용 설명 (선택 사항)', externalKnowledgeId: '외부 지식 ID', - externalKnowledgeIdPlaceholder: '지식 ID를 입력하십시오.', + externalKnowledgeIdPlaceholder: '지식 ID 를 입력하십시오.', allExternalTip: '외부 지식만 사용하는 경우 사용자는 리랭크 모델을 사용할지 여부를 선택할 수 있습니다. 활성화하지 않으면 검색된 청크가 점수에 따라 정렬됩니다. 서로 다른 기술 자료의 검색 전략이 일관되지 않으면 부정확합니다.', - externalAPIPanelDescription: '외부 지식 API는 Dify 외부의 기술 자료에 연결하고 해당 기술 자료에서 지식을 검색하는 데 사용됩니다.', - noExternalKnowledge: '아직 외부 지식 API가 없으므로 여기를 클릭하여 생성하십시오.', + externalAPIPanelDescription: '외부 지식 API 는 Dify 외부의 기술 자료에 연결하고 해당 기술 자료에서 지식을 검색하는 데 사용됩니다.', + noExternalKnowledge: '아직 외부 지식 API 가 없으므로 여기를 클릭하여 생성하십시오.', chunkingMode: { - parentChild: '부모-자식', + parentChild: '부모 - 자식', general: '일반', }, parentMode: { @@ -164,7 +164,7 @@ const translation = { localDocs: '로컬 문서', preprocessDocument: '{{숫자}} 문서 전처리', enable: '사용', - documentsDisabled: '{{num}} 문서 사용 안 함 - 30일 이상 비활성 상태', + documentsDisabled: '{{num}} 문서 사용 안 함 - 30 일 이상 비활성 상태', allKnowledge: '모든 지식', allKnowledgeDescription: '이 작업 영역의 모든 정보를 표시하려면 선택합니다. 워크스페이스 소유자만 모든 기술 자료를 관리할 수 있습니다.', metadata: { diff --git a/web/i18n/ko-KR/education.ts b/web/i18n/ko-KR/education.ts index 78e4be7052..eba00b0f9f 100644 --- a/web/i18n/ko-KR/education.ts +++ b/web/i18n/ko-KR/education.ts @@ -26,15 +26,15 @@ const translation = { privacyPolicy: '개인정보 보호정책', }, option: { - inSchool: '나는 제공된 기관에 재학 중이거나 고용되어 있음을 확인합니다. Dify는 재학증명서나 고용증명서를 요청할 수 있습니다. 만약 내가 자격을 허위로 진술하면, 나는 내 교육 상태에 따라 처음 면제된 수수료를 지불하기로 동의합니다.', - age: '나는 최소한 18세 이상임을 확인합니다.', + inSchool: '나는 제공된 기관에 재학 중이거나 고용되어 있음을 확인합니다. Dify 는 재학증명서나 고용증명서를 요청할 수 있습니다. 만약 내가 자격을 허위로 진술하면, 나는 내 교육 상태에 따라 처음 면제된 수수료를 지불하기로 동의합니다.', + age: '나는 최소한 18 세 이상임을 확인합니다.', }, title: '약관 및 동의사항', }, }, submit: '제출', - rejectContent: '안타깝게도, 귀하는 교육 인증 상태에 적합하지 않으므로 이 이메일 주소를 사용할 경우 Dify Professional Plan의 독점 100% 쿠폰을 받을 수 없습니다.', - successContent: '귀하의 계정에 Dify Professional 플랜을 위한 100% 할인 쿠폰을 발급했습니다. 이 쿠폰은 1년간 유효하므로 유효 기간 내에 사용해 주시기 바랍니다.', + rejectContent: '안타깝게도, 귀하는 교육 인증 상태에 적합하지 않으므로 이 이메일 주소를 사용할 경우 Dify Professional Plan 의 독점 100% 쿠폰을 받을 수 없습니다.', + successContent: '귀하의 계정에 Dify Professional 플랜을 위한 100% 할인 쿠폰을 발급했습니다. 이 쿠폰은 1 년간 유효하므로 유효 기간 내에 사용해 주시기 바랍니다.', currentSigned: '현재 로그인 중입니다', toVerified: '교육 인증 받기', rejectTitle: '귀하의 Dify 교육 인증이 거부되었습니다.', diff --git a/web/i18n/ko-KR/explore.ts b/web/i18n/ko-KR/explore.ts index 5ae1a34643..bc6438af2b 100644 --- a/web/i18n/ko-KR/explore.ts +++ b/web/i18n/ko-KR/explore.ts @@ -16,7 +16,7 @@ const translation = { }, }, apps: { - title: 'Dify로 앱 탐색', + title: 'Dify 로 앱 탐색', description: '이 템플릿 앱을 즉시 사용하거나 템플릿을 기반으로 고유한 앱을 사용자 정의하세요.', allCategories: '모든 카테고리', }, diff --git a/web/i18n/ko-KR/login.ts b/web/i18n/ko-KR/login.ts index 4fbd5f5522..da044554bc 100644 --- a/web/i18n/ko-KR/login.ts +++ b/web/i18n/ko-KR/login.ts @@ -1,6 +1,6 @@ const translation = { pageTitle: '시작하기 🎉', - welcome: 'Dify에 오신 것을 환영합니다. 계속하려면 로그인하세요.', + welcome: 'Dify 에 오신 것을 환영합니다. 계속하려면 로그인하세요.', email: '이메일 주소', emailPlaceholder: '이메일 주소를 입력하세요', password: '비밀번호', @@ -19,13 +19,13 @@ const translation = { invitationCodePlaceholder: '초대 코드를 입력하세요', interfaceLanguage: '인터페이스 언어', timezone: '시간대', - go: 'Dify로 이동', + go: 'Dify 로 이동', sendUsMail: '간단한 소개를 메일로 보내주시면 초대 요청을 처리해드립니다.', acceptPP: '개인정보 처리 방침에 동의합니다.', reset: '비밀번호를 재설정하려면 다음 명령을 실행하세요:', - withGitHub: 'GitHub로 계속', - withGoogle: 'Google로 계속', - rightTitle: 'LLM의 최대 잠재력을 발휘하세요', + withGitHub: 'GitHub 로 계속', + withGoogle: 'Google 로 계속', + rightTitle: 'LLM 의 최대 잠재력을 발휘하세요', rightDesc: '매력적이고 조작 가능하며 개선 가능한 AI 애플리케이션을 쉽게 구축하세요.', tos: '이용약관', pp: '개인정보 처리 방침', @@ -52,33 +52,33 @@ const translation = { emailInValid: '유효한 이메일 주소를 입력하세요.', nameEmpty: '사용자 이름을 입력하세요.', passwordEmpty: '비밀번호를 입력하세요.', - passwordInvalid: '비밀번호는 문자와 숫자를 포함하고 8자 이상이어야 합니다.', - passwordLengthInValid: '비밀번호는 8자 이상이어야 합니다.', + passwordInvalid: '비밀번호는 문자와 숫자를 포함하고 8 자 이상이어야 합니다.', + passwordLengthInValid: '비밀번호는 8 자 이상이어야 합니다.', registrationNotAllowed: '계정을 찾을 수 없습니다. 등록하려면 시스템 관리자에게 문의하십시오.', }, license: { - tip: 'Dify Community Edition을 시작하기 전에 GitHub의', + tip: 'Dify Community Edition 을 시작하기 전에 GitHub 의', link: '오픈 소스 라이선스', }, join: '가입하기', joinTipStart: '당신을 초대합니다.', joinTipEnd: '팀에 가입하세요.', invalid: '링크의 유효 기간이 만료되었습니다.', - explore: 'Dify를 탐색하세요', + explore: 'Dify 를 탐색하세요', activatedTipStart: '이제', activatedTipEnd: '팀에 가입되었습니다.', activated: '지금 로그인하세요', adminInitPassword: '관리자 초기화 비밀번호', validate: '확인', - sso: 'SSO로 계속하기', + sso: 'SSO 로 계속하기', checkCode: { verify: '확인', verificationCode: '인증 코드', tips: '{{email}}로 인증 코드를 보내드립니다.', - validTime: '코드는 5분 동안 유효합니다', + validTime: '코드는 5 분 동안 유효합니다', checkYourEmail: '이메일 주소 확인', invalidCode: '유효하지 않은 코드', - verificationCodePlaceholder: '6자리 코드 입력', + verificationCodePlaceholder: '6 자리 코드 입력', emptyCode: '코드가 필요합니다.', useAnotherMethod: '다른 방법 사용', didNotReceiveCode: '코드를 받지 못하셨나요?', @@ -89,7 +89,7 @@ const translation = { useVerificationCode: '인증 코드 사용', continueWithCode: '코드로 계속하기', usePassword: '비밀번호 사용', - withSSO: 'SSO로 계속하기', + withSSO: 'SSO 로 계속하기', backToLogin: '로그인으로 돌아가기', resetPassword: '비밀번호 재설정', setYourAccount: '계정 설정', @@ -98,13 +98,13 @@ const translation = { changePasswordBtn: '비밀번호 설정', enterYourName: '사용자 이름을 입력해 주세요', noLoginMethodTip: '인증 방법을 추가하려면 시스템 관리자에게 문의하십시오.', - resetPasswordDesc: 'Dify에 가입할 때 사용한 이메일을 입력하면 비밀번호 재설정 이메일을 보내드립니다.', - licenseInactiveTip: '작업 영역에 대한 Dify Enterprise 라이선스가 비활성 상태입니다. Dify를 계속 사용하려면 관리자에게 문의하십시오.', + resetPasswordDesc: 'Dify 에 가입할 때 사용한 이메일을 입력하면 비밀번호 재설정 이메일을 보내드립니다.', + licenseInactiveTip: '작업 영역에 대한 Dify Enterprise 라이선스가 비활성 상태입니다. Dify 를 계속 사용하려면 관리자에게 문의하십시오.', licenseLost: '라이센스 분실', - licenseLostTip: 'Dify 라이선스 서버에 연결하지 못했습니다. Dify를 계속 사용하려면 관리자에게 문의하십시오.', + licenseLostTip: 'Dify 라이선스 서버에 연결하지 못했습니다. Dify 를 계속 사용하려면 관리자에게 문의하십시오.', licenseInactive: 'License Inactive(라이선스 비활성)', licenseExpired: '라이센스가 만료되었습니다.', - licenseExpiredTip: '작업 영역에 대한 Dify Enterprise 라이선스가 만료되었습니다. Dify를 계속 사용하려면 관리자에게 문의하십시오.', + licenseExpiredTip: '작업 영역에 대한 Dify Enterprise 라이선스가 만료되었습니다. Dify 를 계속 사용하려면 관리자에게 문의하십시오.', webapp: { noLoginMethod: '웹 애플리케이션에 대한 인증 방법이 구성되어 있지 않습니다.', disabled: '웹앱 인증이 비활성화되었습니다. 이를 활성화하려면 시스템 관리자에게 문의하십시오. 앱을 직접 사용해 볼 수 있습니다.', diff --git a/web/i18n/ko-KR/plugin.ts b/web/i18n/ko-KR/plugin.ts index 8d823136d0..9fae9a71ac 100644 --- a/web/i18n/ko-KR/plugin.ts +++ b/web/i18n/ko-KR/plugin.ts @@ -18,7 +18,7 @@ const translation = { source: { marketplace: '마켓플레이스에서 설치', local: '로컬 패키지 파일에서 설치', - github: 'GitHub에서 설치', + github: 'GitHub 에서 설치', }, noInstalled: '설치된 플러그인이 없습니다.', notFound: '플러그인을 찾을 수 없습니다.', @@ -32,7 +32,7 @@ const translation = { categoryTip: { marketplace: '마켓플레이스에서 설치됨', debugging: '디버깅 플러그인', - github: 'Github에서 설치됨', + github: 'Github 에서 설치됨', local: '로컬 플러그인', }, operation: { @@ -56,7 +56,7 @@ const translation = { settings: '사용자 설정', unsupportedContent2: '버전을 전환하려면 클릭합니다.', uninstalledTitle: '도구가 설치되지 않음', - descriptionPlaceholder: '도구의 용도에 대한 간략한 설명(예: 특정 위치의 온도 가져오기).', + descriptionPlaceholder: '도구의 용도에 대한 간략한 설명 (예: 특정 위치의 온도 가져오기).', title: '추가 도구', toolLabel: '도구', placeholder: '도구 선택...', @@ -141,9 +141,9 @@ const translation = { installFromGitHub: { uploadFailed: '업로드 실패', selectVersionPlaceholder: '버전을 선택하세요.', - installPlugin: 'GitHub에서 플러그인 설치', + installPlugin: 'GitHub 에서 플러그인 설치', installFailed: '설치 실패', - updatePlugin: 'GitHub에서 플러그인 업데이트', + updatePlugin: 'GitHub 에서 플러그인 업데이트', selectPackage: '패키지 선택', gitHubRepo: 'GitHub 리포지토리', selectPackagePlaceholder: '패키지를 선택하세요.', @@ -161,9 +161,9 @@ const translation = { title: '플러그인 설치', }, error: { - noReleasesFound: '릴리스를 찾을 수 없습니다. GitHub 리포지토리 또는 입력 URL을 확인하세요.', + noReleasesFound: '릴리스를 찾을 수 없습니다. GitHub 리포지토리 또는 입력 URL 을 확인하세요.', fetchReleasesError: '릴리스를 검색할 수 없습니다. 나중에 다시 시도하십시오.', - inValidGitHubUrl: '잘못된 GitHub URL입니다. 유효한 URL을 https://github.com/owner/repo 형식으로 입력하십시오.', + inValidGitHubUrl: '잘못된 GitHub URL 입니다. 유효한 URL 을 https://github.com/owner/repo 형식으로 입력하십시오.', }, marketplace: { sortOption: { @@ -178,10 +178,10 @@ const translation = { difyMarketplace: 'Dify 마켓플레이스', pluginsResult: '{{num}} 결과', discover: '발견하다', - moreFrom: 'Marketplace에서 더 보기', + moreFrom: 'Marketplace 에서 더 보기', sortBy: '정렬', and: '그리고', - verifiedTip: 'Dify에 의해 확인됨', + verifiedTip: 'Dify 에 의해 확인됨', partnerTip: 'Dify 파트너에 의해 확인됨', }, task: { @@ -199,14 +199,14 @@ const translation = { installFrom: '에서 설치', allCategories: '모든 카테고리', submitPlugin: '플러그인 제출', - findMoreInMarketplace: 'Marketplace에서 더 알아보기', + findMoreInMarketplace: 'Marketplace 에서 더 알아보기', searchCategories: '검색 카테고리', search: '검색', - searchInMarketplace: 'Marketplace에서 검색', + searchInMarketplace: 'Marketplace 에서 검색', from: '보낸 사람', searchPlugins: '검색 플러그인', install: '{{num}} 설치', - fromMarketplace: 'Marketplace에서', + fromMarketplace: 'Marketplace 에서', metadata: { title: '플러그인', }, diff --git a/web/i18n/ko-KR/share-app.ts b/web/i18n/ko-KR/share-app.ts index 8474bc554e..1ee44f2816 100644 --- a/web/i18n/ko-KR/share-app.ts +++ b/web/i18n/ko-KR/share-app.ts @@ -51,7 +51,7 @@ const translation = { run: '실행', copy: '복사', resultTitle: 'AI 완성', - noData: 'AI가 필요한 내용을 제공할 것입니다.', + noData: 'AI 가 필요한 내용을 제공할 것입니다.', csvUploadTitle: 'CSV 파일을 여기로 끌어다 놓거나', browse: '찾아보기', csvStructureTitle: 'CSV 파일은 다음 구조를 따라야 합니다:', @@ -65,7 +65,7 @@ const translation = { errorMsg: { empty: '업로드된 파일에 컨텐츠를 입력해주세요.', fileStructNotMatch: '업로드된 CSV 파일이 구조와 일치하지 않습니다.', - emptyLine: '줄 {{rowIndex}}이(가) 비어 있습니다.', + emptyLine: '줄 {{rowIndex}}이 (가) 비어 있습니다.', invalidLine: '줄 {{rowIndex}}: {{varName}}의 값은 비워둘 수 없습니다.', moreThanMaxLengthLine: '줄 {{rowIndex}}: {{varName}}의 값은 {{maxLength}}자를 초과할 수 없습니다.', atLeastOne: '업로드된 파일에는 적어도 한 줄의 입력이 필요합니다.', diff --git a/web/i18n/ko-KR/time.ts b/web/i18n/ko-KR/time.ts index 78e825d1ba..172bb78bd6 100644 --- a/web/i18n/ko-KR/time.ts +++ b/web/i18n/ko-KR/time.ts @@ -9,18 +9,18 @@ const translation = { Mon: '몬', }, months: { - May: '5월', - January: '1월', - August: '8월', - July: '7월', - April: '4월', - October: '10월', - December: '12월', - February: '2월', - June: '6월', - November: '11월', - March: '3월', - September: '9월', + May: '5 월', + January: '1 월', + August: '8 월', + July: '7 월', + April: '4 월', + October: '10 월', + December: '12 월', + February: '2 월', + June: '6 월', + November: '11 월', + March: '3 월', + September: '9 월', }, operation: { pickDate: '날짜 선택', diff --git a/web/i18n/ko-KR/tools.ts b/web/i18n/ko-KR/tools.ts index b526de6c06..45c63b5f80 100644 --- a/web/i18n/ko-KR/tools.ts +++ b/web/i18n/ko-KR/tools.ts @@ -9,7 +9,7 @@ const translation = { workflow: '워크플로우', }, contribute: { - line1: '저는 Dify에', + line1: '저는 Dify 에', line2: '도구를 기여하는데 관심이 있습니다.', viewGuide: '가이드 보기', }, @@ -47,9 +47,9 @@ const translation = { schema: '스키마', schemaPlaceHolder: '여기에 OpenAPI 스키마를 입력하세요', viewSchemaSpec: 'OpenAPI-Swagger 명세 보기', - importFromUrl: 'URL에서 가져오기', + importFromUrl: 'URL 에서 가져오기', importFromUrlPlaceHolder: 'https://...', - urlError: '유효한 URL을 입력하세요', + urlError: '유효한 URL 을 입력하세요', examples: '예시', exampleOptions: { json: '날씨 (JSON)', @@ -96,7 +96,7 @@ const translation = { methodSetting: '설정', methodSettingTip: '도구 설정에서 사용자가 기입', methodParameter: '파라미터', - methodParameterTip: '추론 중에 LLM이 기입', + methodParameterTip: '추론 중에 LLM 이 기입', label: '태그', labelPlaceholder: '태그를 선택하세요.(선택사항)', description: '설명', diff --git a/web/i18n/ko-KR/workflow.ts b/web/i18n/ko-KR/workflow.ts index 3cf22dfe13..a1c08eef4d 100644 --- a/web/i18n/ko-KR/workflow.ts +++ b/web/i18n/ko-KR/workflow.ts @@ -101,19 +101,19 @@ const translation = { ImageUploadLegacyTip: '이제 시작 양식에서 파일 형식 변수를 만들 수 있습니다. 앞으로 이미지 업로드 기능은 더 이상 지원되지 않습니다.', importWarning: '주의', importWarningDetails: 'DSL 버전 차이는 특정 기능에 영향을 미칠 수 있습니다.', - openInExplore: 'Explore에서 열기', + openInExplore: 'Explore 에서 열기', onFailure: '실패 시', addFailureBranch: '실패 분기 추가', noHistory: '이력 없음', loadMore: '더 많은 워크플로우 로드', publishUpdate: '업데이트 게시', - exportJPEG: 'JPEG로 내보내기', + exportJPEG: 'JPEG 로 내보내기', exitVersions: '종료 버전', exportImage: '이미지 내보내기', noExist: '해당 변수가 없습니다.', - exportSVG: 'SVG로 내보내기', + exportSVG: 'SVG 로 내보내기', versionHistory: '버전 기록', - exportPNG: 'PNG로 내보내기', + exportPNG: 'PNG 로 내보내기', referenceVar: '참조 변수', }, env: { @@ -139,7 +139,7 @@ const translation = { }, chatVariable: { panelTitle: '대화 변수', - panelDescription: '대화 변수는 LLM이 기억해야 할 대화 기록, 업로드된 파일, 사용자 선호도 등의 상호작용 정보를 저장하는 데 사용됩니다. 이들은 읽기 및 쓰기가 가능합니다.', + panelDescription: '대화 변수는 LLM 이 기억해야 할 대화 기록, 업로드된 파일, 사용자 선호도 등의 상호작용 정보를 저장하는 데 사용됩니다. 이들은 읽기 및 쓰기가 가능합니다.', docLink: '자세한 내용은 문서를 참조하세요.', button: '변수 추가', modal: { @@ -152,7 +152,7 @@ const translation = { valuePlaceholder: '기본값, 설정하지 않으려면 비워두세요', description: '설명', descriptionPlaceholder: '변수에 대해 설명하세요', - editInJSON: 'JSON으로 편집', + editInJSON: 'JSON 으로 편집', oneByOne: '하나씩 추가', editInForm: '양식에서 편집', arrayValue: '값', @@ -193,7 +193,7 @@ const translation = { errorMsg: { fieldRequired: '{{field}}가 필요합니다', authRequired: '인증이 필요합니다', - invalidJson: '{{field}}는 잘못된 JSON입니다', + invalidJson: '{{field}}는 잘못된 JSON 입니다', fields: { variable: '변수 이름', variableValue: '변수 값', @@ -203,9 +203,9 @@ const translation = { visionVariable: '비전 변수', }, invalidVariable: '잘못된 변수', - rerankModelRequired: 'Rerank Model을 켜기 전에 설정에서 모델이 성공적으로 구성되었는지 확인하십시오.', + rerankModelRequired: 'Rerank Model 을 켜기 전에 설정에서 모델이 성공적으로 구성되었는지 확인하십시오.', noValidTool: '{{field}} 유효한 도구가 선택되지 않았습니다.', - toolParameterRequired: '{{field}}: 매개변수 [{{param}}]이 필요합니다.', + toolParameterRequired: '{{field}}: 매개변수 [{{param}}] 이 필요합니다.', }, singleRun: { testRun: '테스트 실행', @@ -263,17 +263,17 @@ const translation = { 'answer': '대화의 답변 내용을 정의합니다', 'llm': '질문에 답하거나 자연어를 처리하기 위해 대형 언어 모델을 호출합니다', 'knowledge-retrieval': '사용자 질문과 관련된 텍스트 콘텐츠를 지식 베이스에서 쿼리할 수 있습니다', - 'question-classifier': '사용자 질문의 분류 조건을 정의합니다. LLM은 분류 설명을 기반으로 대화의 진행 방식을 정의할 수 있습니다', + 'question-classifier': '사용자 질문의 분류 조건을 정의합니다. LLM 은 분류 설명을 기반으로 대화의 진행 방식을 정의할 수 있습니다', 'if-else': 'if/else 조건을 기반으로 워크플로우를 두 가지 분기로 나눌 수 있습니다', 'code': '사용자 정의 논리를 구현하기 위해 Python 또는 NodeJS 코드를 실행합니다', 'template-transform': 'Jinja 템플릿 구문을 사용하여 데이터를 문자열로 변환합니다', 'http-request': 'HTTP 프로토콜을 통해 서버 요청을 보낼 수 있습니다', 'variable-assigner': '다중 분기 변수들을 하나의 변수로 집계하여 다운스트림 노드의 통합 구성을 가능하게 합니다.', - 'assigner': '변수 할당 노드는 쓰기 가능한 변수(대화 변수 등)에 값을 할당하는 데 사용됩니다.', + 'assigner': '변수 할당 노드는 쓰기 가능한 변수 (대화 변수 등) 에 값을 할당하는 데 사용됩니다.', 'variable-aggregator': '다중 분기 변수들을 하나의 변수로 집계하여 다운스트림 노드의 통합 구성을 가능하게 합니다.', 'iteration': '목록 객체에서 여러 단계를 수행하여 모든 결과가 출력될 때까지 반복합니다.', - 'parameter-extractor': '도구 호출 또는 HTTP 요청을 위해 자연어에서 구조화된 매개변수를 추출하기 위해 LLM을 사용합니다.', - 'document-extractor': '업로드된 문서를 LLM에서 쉽게 이해할 수 있는 텍스트 콘텐츠로 구문 분석하는 데 사용됩니다.', + 'parameter-extractor': '도구 호출 또는 HTTP 요청을 위해 자연어에서 구조화된 매개변수를 추출하기 위해 LLM 을 사용합니다.', + 'document-extractor': '업로드된 문서를 LLM 에서 쉽게 이해할 수 있는 텍스트 콘텐츠로 구문 분석하는 데 사용됩니다.', 'list-operator': '배열 내용을 필터링하거나 정렬하는 데 사용됩니다.', 'agent': '질문에 답하거나 자연어를 처리하기 위해 대규모 언어 모델을 호출하는 경우', 'loop': '종료 조건이 충족되거나 최대 반복 횟수에 도달할 때까지 논리 루프를 실행합니다.', @@ -282,8 +282,8 @@ const translation = { operator: { zoomIn: '확대', zoomOut: '축소', - zoomTo50: '50%로 확대', - zoomTo100: '100%로 확대', + zoomTo50: '50% 로 확대', + zoomTo100: '100% 로 확대', zoomToFit: '화면에 맞게 확대', }, panel: { @@ -336,9 +336,9 @@ const translation = { failBranch: { title: '실패 분기', desc: '오류가 발생하면 예외 분기를 실행합니다', - customize: '캔버스로 이동하여 fail branch logic를 사용자 지정합니다.', + customize: '캔버스로 이동하여 fail branch logic 를 사용자 지정합니다.', inLog: '노드 예외는 실패 분기를 자동으로 실행합니다. 노드 출력은 오류 유형 및 오류 메시지를 반환하고 다운스트림으로 전달합니다.', - customizeTip: 'fail 분기가 활성화되면 노드에서 throw된 예외가 프로세스를 종료하지 않습니다. 대신 미리 정의된 실패 분기를 자동으로 실행하여 오류 메시지, 보고서, 수정 사항을 유연하게 제공하거나 작업을 건너뛸 수 있습니다.', + customizeTip: 'fail 분기가 활성화되면 노드에서 throw 된 예외가 프로세스를 종료하지 않습니다. 대신 미리 정의된 실패 분기를 자동으로 실행하여 오류 메시지, 보고서, 수정 사항을 유연하게 제공하거나 작업을 건너뛸 수 있습니다.', }, partialSucceeded: { tip: '프로세스에 {{num}} 노드가 비정상적으로 실행 중입니다. 추적으로 이동하여 로그를 확인하십시오.', @@ -397,7 +397,7 @@ const translation = { variables: '변수', context: '컨텍스트', contextTooltip: '컨텍스트로 지식을 가져올 수 있습니다', - notSetContextInPromptTip: '컨텍스트 기능을 활성화하려면 PROMPT에 컨텍스트 변수를 입력하세요.', + notSetContextInPromptTip: '컨텍스트 기능을 활성화하려면 PROMPT 에 컨텍스트 변수를 입력하세요.', prompt: '프롬프트', roleDescription: { system: '대화를 위한 고급 지침 제공', @@ -419,7 +419,7 @@ const translation = { singleRun: { variable: '변수', }, - sysQueryInUser: '사용자 메시지에 sys.query가 필요합니다', + sysQueryInUser: '사용자 메시지에 sys.query 가 필요합니다', jsonSchema: { warningTips: { saveSchema: '현재 필드의 편집을 완료한 후 스키마를 저장하세요.', @@ -446,7 +446,7 @@ const translation = { regenerate: '재생하다', required: '필수', doc: '구조화된 출력에 대해 더 알아보세요.', - import: 'JSON에서 가져오기', + import: 'JSON 에서 가져오기', }, }, knowledgeRetrieval: { @@ -491,12 +491,12 @@ const translation = { http: { inputVars: '입력 변수', api: 'API', - apiPlaceholder: 'URL을 입력하세요, 변수를 삽입하려면 ‘/’를 입력하세요', - notStartWithHttp: 'API는 http:// 또는 https://로 시작해야 합니다', + apiPlaceholder: 'URL 을 입력하세요, 변수를 삽입하려면‘/’를 입력하세요', + notStartWithHttp: 'API 는 http:// 또는 https://로 시작해야 합니다', key: '키', value: '값', bulkEdit: '일괄 편집', - keyValueEdit: '키-값 편집', + keyValueEdit: '키 - 값 편집', headers: '헤더', params: '매개변수', body: '본문', @@ -532,7 +532,7 @@ const translation = { binaryFileVariable: '바이너리 파일 변수', extractListPlaceholder: '목록 항목 인덱스 입력, \'/\' 변수 삽입', curl: { - title: 'cURL에서 가져오기', + title: 'cURL 에서 가져오기', placeholder: '여기에 cURL 문자열 붙여 넣기', }, }, @@ -546,7 +546,7 @@ const translation = { templateTransform: { inputVars: '입력 변수', code: '코드', - codeSupportTip: 'Jinja2만 지원합니다', + codeSupportTip: 'Jinja2 만 지원합니다', outputVars: { output: '변환된 내용', }, @@ -568,8 +568,8 @@ const translation = { 'is not': '아니다', 'empty': '비어 있음', 'not empty': '비어 있지 않음', - 'null': 'null임', - 'not null': 'null이 아님', + 'null': 'null 임', + 'not null': 'null 이 아님', 'regex match': '정규식 일치', 'in': '안으로', 'exists': '존재', @@ -699,7 +699,7 @@ const translation = { advancedSetting: '고급 설정', reasoningMode: '추론 모드', reasoningModeTip: '모델의 함수 호출 또는 프롬프트에 대한 지시 응답 능력을 기반으로 적절한 추론 모드를 선택할 수 있습니다.', - isSuccess: '성공 여부. 성공 시 값은 1이고, 실패 시 값은 0입니다.', + isSuccess: '성공 여부. 성공 시 값은 1 이고, 실패 시 값은 0 입니다.', errorReason: '오류 원인', }, iteration: { @@ -804,7 +804,7 @@ const translation = { files: { url: '이미지 URL', upload_file_id: '파일 ID 업로드', - transfer_method: '전송 방법. 값이 remote_url 또는 local_file입니다.', + transfer_method: '전송 방법. 값이 remote_url 또는 local_file 입니다.', type: '지원 유형. 이제 이미지만 지원합니다.', title: '에이전트 생성 파일', }, @@ -826,8 +826,8 @@ const translation = { toolNotAuthorizedTooltip: '{{도구}} 권한이 부여되지 않음', strategyNotFoundDesc: '설치된 플러그인 버전은 이 전략을 제공하지 않습니다.', maxIterations: '최대 반복 횟수', - pluginNotFoundDesc: '이 플러그인은 GitHub에서 설치됩니다. 플러그인으로 이동하여 다시 설치하십시오.', - pluginNotInstalledDesc: '이 플러그인은 GitHub에서 설치됩니다. 플러그인으로 이동하여 다시 설치하십시오.', + pluginNotFoundDesc: '이 플러그인은 GitHub 에서 설치됩니다. 플러그인으로 이동하여 다시 설치하십시오.', + pluginNotInstalledDesc: '이 플러그인은 GitHub 에서 설치됩니다. 플러그인으로 이동하여 다시 설치하십시오.', strategyNotInstallTooltip: '{{strategy}}가 설치되지 않았습니다.', tools: '도구', unsupportedStrategy: '지원되지 않는 전략', @@ -868,7 +868,7 @@ const translation = { initialLoopVariables: '초기 루프 변수', breakConditionTip: '종료 조건과 대화 변수가 있는 루프 내에서만 변수를 참조할 수 있습니다.', currentLoopCount: '현재 루프 카운트: {{count}}', - loopMaxCountError: '유효한 최대 루프 수를 입력하십시오. 범위는 1에서 {{maxCount}}입니다.', + loopMaxCountError: '유효한 최대 루프 수를 입력하십시오. 범위는 1 에서 {{maxCount}}입니다.', totalLoopCount: '총 루프 횟수: {{count}}', variableName: '변수 이름', loopNode: '루프 노드', diff --git a/web/i18n/language.ts b/web/i18n/language.ts index 87027a7951..a31f9e9c4b 100644 --- a/web/i18n/language.ts +++ b/web/i18n/language.ts @@ -92,7 +92,7 @@ export const NOTICE_I18N = { ja_JP: 'Our system will be unavailable from 19:00 to 24:00 UTC on August 28 for an upgrade. For questions, kindly contact our support team (support@dify.ai). We value your patience.', ko_KR: - '시스템이 업그레이드를 위해 UTC 시간대로 8월 28일 19:00 ~ 24:00에 사용 불가될 예정입니다. 질문이 있으시면 지원 팀에 연락주세요 (support@dify.ai). 최선을 다해 답변해드리겠습니다.', + '시스템이 업그레이드를 위해 UTC 시간대로 8 월 28 일 19:00 ~ 24:00 에 사용 불가될 예정입니다. 질문이 있으시면 지원 팀에 연락주세요 (support@dify.ai). 최선을 다해 답변해드리겠습니다.', pl_PL: 'Nasz system będzie niedostępny od 19:00 do 24:00 UTC 28 sierpnia w celu aktualizacji. W przypadku pytań prosimy o kontakt z naszym zespołem wsparcia (support@dify.ai). Doceniamy Twoją cierpliwość.', uk_UA: diff --git a/web/i18n/vi-VN/workflow.ts b/web/i18n/vi-VN/workflow.ts index 2e0acf0c4d..448a4657a4 100644 --- a/web/i18n/vi-VN/workflow.ts +++ b/web/i18n/vi-VN/workflow.ts @@ -228,7 +228,7 @@ const translation = { 'logic': 'Logic', 'transform': 'Chuyển đổi', 'utilities': 'Tiện ích', - 'noResult': 'Không tìm thấy kế;t quả phù hợp', + 'noResult': 'Không tìm thấy kế. t quả phù hợp', 'searchTool': 'Công cụ tìm kiếm', 'agent': 'Chiến lược đại lý', 'plugin': 'Plugin', diff --git a/web/i18n/zh-Hans/app-api.ts b/web/i18n/zh-Hans/app-api.ts index f59d9065a6..70b8413244 100644 --- a/web/i18n/zh-Hans/app-api.ts +++ b/web/i18n/zh-Hans/app-api.ts @@ -41,7 +41,7 @@ const translation = { messageFeedbackApi: '消息反馈(点赞)', messageFeedbackApiTip: '代表最终用户对返回消息进行评价,可以点赞与点踩,该数据将在“日志与标注”页中可见,并用于后续的模型微调。', messageIDTip: '消息 ID', - ratingTip: 'like 或 dislike, 空值为撤销', + ratingTip: 'like 或 dislike,空值为撤销', parametersApi: '获取应用配置信息', parametersApiTip: '获取已配置的 Input 参数,包括变量名、字段名称、类型与默认值。通常用于客户端加载后显示这些字段的表单或填入默认值。', }, @@ -58,7 +58,7 @@ const translation = { messageFeedbackApi: '消息反馈(点赞)', messageFeedbackApiTip: '代表最终用户对返回消息进行评价,可以点赞与点踩,该数据将在“日志与标注”页中可见,并用于后续的模型微调。', messageIDTip: '消息 ID', - ratingTip: 'like 或 dislike, 空值为撤销', + ratingTip: 'like 或 dislike,空值为撤销', chatMsgHistoryApi: '获取会话历史消息', chatMsgHistoryApiTip: '滚动加载形式返回历史聊天记录,第一页返回最新 `limit` 条,即:倒序返回。', chatMsgHistoryConversationIdTip: '会话 ID', diff --git a/web/i18n/zh-Hans/app-debug.ts b/web/i18n/zh-Hans/app-debug.ts index af221a926c..06e737c3c3 100644 --- a/web/i18n/zh-Hans/app-debug.ts +++ b/web/i18n/zh-Hans/app-debug.ts @@ -123,7 +123,7 @@ const translation = { ok: '好的', contextVarNotEmpty: '上下文查询变量不能为空', deleteContextVarTitle: '删除变量“{{varName}}”?', - deleteContextVarTip: '该变量已被设置为上下文查询变量,删除该变量将影响知识库的正常使用。 如果您仍需要删除它,请在上下文部分中重新选择它。', + deleteContextVarTip: '该变量已被设置为上下文查询变量,删除该变量将影响知识库的正常使用。如果您仍需要删除它,请在上下文部分中重新选择它。', }, }, tools: { @@ -402,9 +402,9 @@ const translation = { visionSettings: { title: '视觉设置', resolution: '分辨率', - resolutionTooltip: `低分辨率模式将使模型接收图像的低分辨率版本,尺寸为512 x 512,并使用65 Tokens 来表示图像。这样可以使API更快地返回响应,并在不需要高细节的用例中消耗更少的输入。 + resolutionTooltip: `低分辨率模式将使模型接收图像的低分辨率版本,尺寸为 512 x 512,并使用 65 Tokens 来表示图像。这样可以使 API 更快地返回响应,并在不需要高细节的用例中消耗更少的输入。 \n - 高分辨率模式将首先允许模型查看低分辨率图像,然后根据输入图像的大小创建512像素的详细裁剪图像。每个详细裁剪图像使用两倍的预算总共为129 Tokens。`, + 高分辨率模式将首先允许模型查看低分辨率图像,然后根据输入图像的大小创建 512 像素的详细裁剪图像。每个详细裁剪图像使用两倍的预算总共为 129 Tokens。`, high: '高', low: '低', uploadMethod: '上传方式', @@ -437,7 +437,7 @@ const translation = { openingQuestion: '开场问题', noDataPlaceHolder: '在对话型应用中,让 AI 主动说第一段话可以拉近与用户间的距离。', - varTip: '你可以使用变量, 试试输入 {{variable}}', + varTip: '你可以使用变量,试试输入 {{variable}}', tooShort: '对话前提示词至少 20 字才能生成开场白', notIncludeKey: '前缀提示词中不包含变量 {{key}}。请在前缀提示词中添加该变量', }, @@ -466,9 +466,9 @@ const translation = { noResult: '输出结果展示在这', datasetConfig: { settingTitle: '召回设置', - knowledgeTip: '点击 “+” 按钮添加知识库', + knowledgeTip: '点击“+”按钮添加知识库', retrieveOneWay: { - title: 'N选1召回', + title: 'N 选 1 召回', description: '根据用户意图和知识库描述,由 Agent 自主判断选择最匹配的单个知识库来查询相关文本,适合知识库区分度大且知识库数量偏少的应用。', }, retrieveMultiWay: { diff --git a/web/i18n/zh-Hans/app-overview.ts b/web/i18n/zh-Hans/app-overview.ts index 1486f9b4c4..a41a86975a 100644 --- a/web/i18n/zh-Hans/app-overview.ts +++ b/web/i18n/zh-Hans/app-overview.ts @@ -1,6 +1,6 @@ const translation = { welcome: { - firstStepTip: '开始之前,', + firstStepTip: '开始之前,', enterKeyTip: '请先在下方输入你的 OpenAI API Key', getKeyTip: '从 OpenAI 获取你的 API Key', placeholder: '你的 OpenAI API Key(例如 sk-xxxx)', @@ -9,11 +9,11 @@ const translation = { cloud: { trial: { title: '您正在使用 {{providerName}} 的试用配额。', - description: '试用配额仅供您测试使用。 在试用配额用完之前,请自行设置模型提供商或购买额外配额。', + description: '试用配额仅供您测试使用。在试用配额用完之前,请自行设置模型提供商或购买额外配额。', }, exhausted: { - title: '您的试用额度已用完,请设置您的APIKey。', - description: '您的试用配额已用完。 请设置您自己的模型提供商或购买额外配额。', + title: '您的试用额度已用完,请设置您的 APIKey。', + description: '您的试用配额已用完。请设置您自己的模型提供商或购买额外配额。', }, }, selfHost: { diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index a634394cfb..bdd7d98d9b 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -23,7 +23,7 @@ const translation = { importFromDSLFile: '文件', importFromDSLUrl: 'URL', importFromDSLUrlPlaceholder: '输入 DSL 文件的 URL', - deleteAppConfirmTitle: '确认删除应用?', + deleteAppConfirmTitle: '确认删除应用?', deleteAppConfirmContent: '删除应用将无法撤销。用户将不能访问你的应用,所有 Prompt 编排配置和日志均将一并被删除。', appDeleted: '应用已删除', @@ -169,12 +169,12 @@ const translation = { publicKey: '公钥', secretKey: '密钥', viewDocsLink: '查看 {{key}} 的文档', - removeConfirmTitle: '删除 {{key}} 配置?', + removeConfirmTitle: '删除 {{key}} 配置?', removeConfirmContent: '当前配置正在使用中,删除它将关闭追踪功能。', }, weave: { title: '编织', - description: 'Weave是一个开源平台,用于评估、测试和监控大型语言模型应用程序。', + description: 'Weave 是一个开源平台,用于评估、测试和监控大型语言模型应用程序。', }, }, appSelector: { diff --git a/web/i18n/zh-Hans/common.ts b/web/i18n/zh-Hans/common.ts index b8e1342fc4..00c8a33837 100644 --- a/web/i18n/zh-Hans/common.ts +++ b/web/i18n/zh-Hans/common.ts @@ -126,7 +126,7 @@ const translation = { '影响常见与罕见词汇使用。\n值较大时,倾向于生成不常见的词汇和表达方式。\n值越小,更倾向于使用常见和普遍接受的词汇或短语。', max_tokens: '单次回复限制 max_tokens', max_tokensTip: - '用于限制回复的最大长度,以 token 为单位。\n较大的值可能会限制给提示词、聊天记录和知识库留出的空间。\n建议将其设置在三分之二以下。\ngpt-4-1106-preview、gpt-4-vision-preview 最大长度 (输入128k,输出4k)', + '用于限制回复的最大长度,以 token 为单位。\n较大的值可能会限制给提示词、聊天记录和知识库留出的空间。\n建议将其设置在三分之二以下。\ngpt-4-1106-preview、gpt-4-vision-preview 最大长度 (输入 128k,输出 4k)', maxTokenSettingTip: '您设置的最大 tokens 数较大,可能会导致 prompt、用户问题、知识库内容没有 token 空间进行处理,建议设置到 2/3 以下。', setToCurrentModelMaxTokenTip: '最大令牌数更新为当前模型最大的令牌数 {{maxToken}} 的 80%。', stop_sequences: '停止序列 stop_sequences', @@ -153,7 +153,7 @@ const translation = { exploreMarketplace: '探索 Marketplace', pluginsTips: '集成第三方插件或创建与 ChatGPT 兼容的 AI 插件。', datasets: '知识库', - datasetsTips: '即将到来: 上传自己的长文本数据,或通过 Webhook 集成自己的数据源', + datasetsTips: '即将到来:上传自己的长文本数据,或通过 Webhook 集成自己的数据源', newApp: '创建应用', newDataset: '创建知识库', tools: '工具', @@ -270,7 +270,7 @@ const translation = { deleteMember: '删除成员', you: '(你)', builderTip: '可以构建和编辑自己的应用程序', - setBuilder: 'Set as builder (设置为构建器)', + setBuilder: 'Set as builder(设置为构建器)', builder: '构建器', }, integrations: { @@ -348,7 +348,7 @@ const translation = { }, embeddingModel: { key: 'Embedding 模型', - tip: '设置知识库文档嵌入处理的默认模型,检索和导入知识库均使用该Embedding模型进行向量化处理,切换后将导致已导入的知识库与问题之间的向量维度不一致,从而导致检索失败。为避免检索失败,请勿随意切换该模型。', + tip: '设置知识库文档嵌入处理的默认模型,检索和导入知识库均使用该 Embedding 模型进行向量化处理,切换后将导致已导入的知识库与问题之间的向量维度不一致,从而导致检索失败。为避免检索失败,请勿随意切换该模型。', required: '请选择 Embedding 模型', }, speechToTextModel: { @@ -384,7 +384,7 @@ const translation = { buyQuota: '购买额度', priorityUse: '优先使用', removeKey: '删除 API 密钥', - tip: '已付费额度将优先考虑。 试用额度将在付费额度用完后使用。', + tip: '已付费额度将优先考虑。试用额度将在付费额度用完后使用。', }, item: { deleteDesc: '{{modelName}} 被用作系统推理模型。删除后部分功能将无法使用。请确认。', @@ -415,7 +415,7 @@ const translation = { getFreeTokens: '获得免费 Tokens', priorityUsing: '优先使用', deprecated: '已弃用', - confirmDelete: '确认删除?', + confirmDelete: '确认删除?', quotaTip: '剩余免费额度', loadPresets: '加载预设', parameters: '参数', @@ -667,7 +667,7 @@ const translation = { imageInput: { dropImageHere: '将图片拖放到此处,或', browse: '浏览', - supportedFormats: '支持PNG、JPG、JPEG、WEBP和GIF格式', + supportedFormats: '支持 PNG、JPG、JPEG、WEBP 和 GIF 格式', }, you: '你', } diff --git a/web/i18n/zh-Hans/dataset-creation.ts b/web/i18n/zh-Hans/dataset-creation.ts index 72e2511bd4..6f4c5af7eb 100644 --- a/web/i18n/zh-Hans/dataset-creation.ts +++ b/web/i18n/zh-Hans/dataset-creation.ts @@ -92,18 +92,18 @@ const translation = { excludePaths: '排除路径', includeOnlyPaths: '仅包含路径', extractOnlyMainContent: '仅提取主要内容(无标题、导航、页脚等)', - exceptionErrorTitle: '运行时发生异常:', + exceptionErrorTitle: '运行时发生异常:', unknownError: '未知错误', - totalPageScraped: '抓取页面总数:', + totalPageScraped: '抓取页面总数:', selectAll: '全选', resetAll: '重置全部', scrapTimeInfo: '总共在 {{time}}秒 内抓取了 {{total}} 个页面', preview: '预览', - maxDepthTooltip: '相对于输入 URL 的最大抓取深度。深度0仅抓取输入 URL 本身的页面,深度1抓取输入 URL 及其后的一层目录(一个 /),依此类推。', + maxDepthTooltip: '相对于输入 URL 的最大抓取深度。深度 0 仅抓取输入 URL 本身的页面,深度 1 抓取输入 URL 及其后的一层目录(一个 /),依此类推。', watercrawlDocLink: '从网站同步', watercrawlDoc: 'Watercrawl 文档', configureWatercrawl: '配置水爬行', - watercrawlTitle: '使用Watercrawl提取网页内容', + watercrawlTitle: '使用 Watercrawl 提取网页内容', }, }, stepTwo: { @@ -121,19 +121,19 @@ const translation = { paragraph: '段落', paragraphTip: '此模式根据分隔符和最大块长度将文本拆分为段落,使用拆分文本作为检索的父块', fullDoc: '全文', - fullDocTip: '整个文档用作父块并直接检索。请注意,出于性能原因,超过10000个标记的文本将被自动截断。', + fullDocTip: '整个文档用作父块并直接检索。请注意,出于性能原因,超过 10000 个标记的文本将被自动截断。', separator: '分段标识符', separatorTip: '分隔符是用于分隔文本的字符。\\n\\n 和 \\n 是常用于分隔段落和行的分隔符。用逗号连接分隔符(\\n\\n,\\n),当段落超过最大块长度时,会按行进行分割。你也可以使用自定义的特殊分隔符(例如 ***)。', separatorPlaceholder: '\\n\\n 用于分段;\\n 用于分行', maxLength: '分段最大长度', maxLengthCheck: '分段最大长度不能大于 {{limit}}', overlap: '分段重叠长度', - overlapTip: '设置分段之间的重叠长度可以保留分段之间的语义关系,提升召回效果。建议设置为最大分段长度的10%-25%', + overlapTip: '设置分段之间的重叠长度可以保留分段之间的语义关系,提升召回效果。建议设置为最大分段长度的 10%-25%', overlapCheck: '分段重叠长度不能大于分段最大长度', rules: '文本预处理规则', removeExtraSpaces: '替换掉连续的空格、换行符和制表符', removeUrlEmails: '删除所有 URL 和电子邮件地址', - removeStopwords: '去除停用词,例如 “a”,“an”,“the” 等', + removeStopwords: '去除停用词,例如“a”,“an”,“the”等', preview: '预览', previewChunk: '预览块', reset: '重置', @@ -141,11 +141,11 @@ const translation = { qualified: '高质量', highQualityTip: '使用高质量模式进行嵌入后,无法切换回经济模式。', recommend: '推荐', - qualifiedTip: '调用嵌入模型处理文档以实现更精确的检索,可以帮助LLM生成高质量的答案。', + qualifiedTip: '调用嵌入模型处理文档以实现更精确的检索,可以帮助 LLM 生成高质量的答案。', warning: '请先完成模型供应商的 API KEY 设置。.', click: '前往设置', economical: '经济', - economicalTip: '每个数据块使用10个关键词进行检索,不会消耗任何tokens,但会以降低检索准确性为代价。', + economicalTip: '每个数据块使用 10 个关键词进行检索,不会消耗任何 tokens,但会以降低检索准确性为代价。', QATitle: '采用 Q&A 分段模式', QATip: '开启后将会消耗额外的 token', QALanguage: '分段使用', diff --git a/web/i18n/zh-Hans/dataset.ts b/web/i18n/zh-Hans/dataset.ts index 064ceb3c03..9b5691ae24 100644 --- a/web/i18n/zh-Hans/dataset.ts +++ b/web/i18n/zh-Hans/dataset.ts @@ -27,7 +27,7 @@ const translation = { createDataset: '创建知识库', noExternalKnowledge: '还没有外部知识库 API,点击此处创建', createExternalAPI: '添加外部知识库 API', - createNewExternalAPI: '创建新的外部知识库API', + createNewExternalAPI: '创建新的外部知识库 API', editExternalAPIFormTitle: '编辑外部知识库 API', editExternalAPITooltipTitle: '个关联知识库', editExternalAPIConfirmWarningContent: { @@ -69,8 +69,8 @@ const translation = { createDatasetIntro: '导入您自己的文本数据或通过 Webhook 实时写入数据以增强 LLM 的上下文。', deleteDatasetConfirmTitle: '要删除知识库吗?', deleteDatasetConfirmContent: - '删除知识库是不可逆的。用户将无法再访问您的知识库,所有的提示配置和日志将被永久删除。', - datasetUsedByApp: '某些应用正在使用该知识库。应用将无法再使用该知识库,所有的提示配置和日志将被永久删除。', + '删除知识库是不可逆的。用户将无法再访问您的知识库,所有的提示配置和日志将被永久删除。', + datasetUsedByApp: '某些应用正在使用该知识库。应用将无法再使用该知识库,所有的提示配置和日志将被永久删除。', datasetDeleted: '知识库已删除', datasetDeleteFailed: '删除知识库失败', selectExternalKnowledgeAPI: { @@ -207,7 +207,7 @@ const translation = { builtIn: '内置', builtInDescription: '内置元数据是系统预定义的元数据,您可以在此处查看和管理内置元数据。', deleteTitle: '确定删除', - deleteContent: '你确定要删除元数据 "{{name}}" 吗?', + deleteContent: '你确定要删除元数据 "{{name}}" 吗?', }, documentMetadata: { metadataToolTip: '元数据是关于文档的数据,用于描述文档的属性。元数据可以帮助您更好地组织和管理文档。', diff --git a/web/i18n/zh-Hans/login.ts b/web/i18n/zh-Hans/login.ts index e2a958ea05..a37fc104eb 100644 --- a/web/i18n/zh-Hans/login.ts +++ b/web/i18n/zh-Hans/login.ts @@ -59,12 +59,12 @@ const translation = { emailInValid: '请输入有效的邮箱地址', nameEmpty: '用户名不能为空', passwordEmpty: '密码不能为空', - passwordInvalid: '密码必须包含字母和数字,且长度不小于8位', + passwordInvalid: '密码必须包含字母和数字,且长度不小于 8 位', passwordLengthInValid: '密码必须至少为 8 个字符', registrationNotAllowed: '账户不存在,请联系系统管理员注册账户', }, license: { - tip: '启动 Dify 社区版之前, 请阅读 GitHub 上的', + tip: '启动 Dify 社区版之前,请阅读 GitHub 上的', link: '开源协议', }, join: '加入 ', diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts index 6648e3b65a..db653913a2 100644 --- a/web/i18n/zh-Hans/plugin.ts +++ b/web/i18n/zh-Hans/plugin.ts @@ -67,7 +67,7 @@ const translation = { endpointsDocLink: '查看文档', endpointsEmpty: '点击 \'+\' 按钮添加 API 端点', endpointDisableTip: '停用 API 端点', - endpointDisableContent: '是否要停用 {{name}} 的 API 端点 ?', + endpointDisableContent: '是否要停用 {{name}} 的 API 端点?', endpointDeleteTip: '移除 API 端点', endpointDeleteContent: '是否要移除 {{name}} ?', endpointModalTitle: '设置 API 端点', @@ -124,7 +124,7 @@ const translation = { pluginInfo: '插件信息', delete: '移除插件', deleteContentLeft: '是否要移除 ', - deleteContentRight: ' 插件?', + deleteContentRight: ' 插件?', usedInApps: '此插件正在 {{num}} 个应用中使用。', }, installModal: { diff --git a/web/i18n/zh-Hans/share-app.ts b/web/i18n/zh-Hans/share-app.ts index 3e89aec041..4ea2ad6f49 100644 --- a/web/i18n/zh-Hans/share-app.ts +++ b/web/i18n/zh-Hans/share-app.ts @@ -68,8 +68,8 @@ const translation = { empty: '上传文件的内容不能为空', fileStructNotMatch: '上传文件的内容与结构不匹配', emptyLine: '第 {{rowIndex}} 行的内容为空', - invalidLine: '第 {{rowIndex}} 行: {{varName}}值必填', - moreThanMaxLengthLine: '第 {{rowIndex}} 行: {{varName}}值超过最大长度 {{maxLength}}', + invalidLine: '第 {{rowIndex}} 行:{{varName}}值必填', + moreThanMaxLengthLine: '第 {{rowIndex}} 行:{{varName}}值超过最大长度 {{maxLength}}', atLeastOne: '上传文件的内容不能少于一条', }, }, diff --git a/web/i18n/zh-Hans/tools.ts b/web/i18n/zh-Hans/tools.ts index 81be870765..9a573ad308 100644 --- a/web/i18n/zh-Hans/tools.ts +++ b/web/i18n/zh-Hans/tools.ts @@ -29,7 +29,7 @@ const translation = { added: '已添加', manageInTools: '去工具列表管理', emptyTitle: '没有可用的工作流工具', - emptyTip: '去 “工作流 -> 发布为工具” 添加', + emptyTip: '去“工作流 -> 发布为工具”添加', emptyTitleCustom: '没有可用的自定义工具', emptyTipCustom: '创建自定义工具', }, @@ -52,8 +52,8 @@ const translation = { urlError: '请输入有效的 URL', examples: '例子', exampleOptions: { - json: '天气(JSON)', - yaml: '宠物商店(YAML)', + json: '天气 (JSON)', + yaml: '宠物商店 (YAML)', blankTemplate: '空白模版', }, availableTools: { @@ -98,7 +98,7 @@ const translation = { methodParameter: 'LLM 填入', methodParameterTip: 'LLM 在推理过程中填写', label: '标签', - labelPlaceholder: '选择标签(可选)', + labelPlaceholder: '选择标签 (可选)', description: '描述', descriptionPlaceholder: '参数意义的描述', }, @@ -135,7 +135,7 @@ const translation = { infoAndSetting: '信息和设置', }, noCustomTool: { - title: '没有自定义工具!', + title: '没有自定义工具!', content: '在此统一添加和管理你的自定义工具,方便构建应用时使用。', createTool: '创建工具', }, diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index b8257d8229..79b9e674fd 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -58,7 +58,7 @@ const translation = { processData: '数据处理', input: '输入', output: '输出', - jinjaEditorPlaceholder: '输入 “/” 或 “{” 插入变量', + jinjaEditorPlaceholder: '输入“/”或“{”插入变量', viewOnly: '只读', showRunHistory: '显示运行历史', enableJinja: '开启支持 Jinja 模板', @@ -271,7 +271,7 @@ const translation = { 'variable-aggregator': '将多路分支的变量聚合为一个变量,以实现下游节点统一配置。', 'iteration': '对列表对象执行多次步骤直至输出所有结果。', 'loop': '循环执行一段逻辑直到满足结束条件或者到达循环次数上限。', - 'loop-end': '相当于“break” 此节点没有配置项,当循环体内运行到此节点后循环终止。', + 'loop-end': '相当于“break”此节点没有配置项,当循环体内运行到此节点后循环终止。', 'parameter-extractor': '利用 LLM 从自然语言内推理提取出结构化参数,用于后置的工具调用或 HTTP 请求。', 'document-extractor': '用于将用户上传的文档解析为 LLM 便于理解的文本内容。', 'list-operator': '用于过滤或排序数组内容。', @@ -538,7 +538,7 @@ const translation = { writePlaceholder: '输入写入超时(以秒为单位)', }, curl: { - title: '导入cURL', + title: '导入 cURL', placeholder: '粘贴 cURL 字符串', }, }, @@ -661,9 +661,9 @@ const translation = { type: '支持类型。现在只支持图片', transfer_method: '传输方式。值为 remote_url 或 local_file', url: '图片链接', - upload_file_id: '上传文件ID', + upload_file_id: '上传文件 ID', }, - json: '工具生成的json', + json: '工具生成的 json', }, }, questionClassifiers: { @@ -788,7 +788,7 @@ const translation = { outputVars: { text: '提取的文本', }, - supportFileTypes: '支持的文件类型: {{types}}。', + supportFileTypes: '支持的文件类型:{{types}}。', learnMore: '了解更多', }, listFilter: { @@ -863,9 +863,9 @@ const translation = { type: '支持类型。现在只支持图片', transfer_method: '传输方式。值为 remote_url 或 local_file', url: '图片链接', - upload_file_id: '上传文件ID', + upload_file_id: '上传文件 ID', }, - json: 'agent 生成的json', + json: 'agent 生成的 json', }, checkList: { strategyNotSelected: '未选择策略', diff --git a/web/i18n/zh-Hant/app-api.ts b/web/i18n/zh-Hant/app-api.ts index 1a2cff7202..db43cd8b77 100644 --- a/web/i18n/zh-Hant/app-api.ts +++ b/web/i18n/zh-Hant/app-api.ts @@ -40,7 +40,7 @@ const translation = { messageFeedbackApi: '訊息反饋(點贊)', messageFeedbackApiTip: '代表終端使用者對返回訊息進行評價,可以點贊與點踩,該資料將在“日誌與標註”頁中可見,並用於後續的模型微調。', messageIDTip: '訊息 ID', - ratingTip: 'like 或 dislike, 空值為撤銷', + ratingTip: 'like 或 dislike,空值為撤銷', parametersApi: '獲取應用配置資訊', parametersApiTip: '獲取已配置的 Input 引數,包括變數名、欄位名稱、型別與預設值。通常用於客戶端載入後顯示這些欄位的表單或填入預設值。', }, @@ -57,7 +57,7 @@ const translation = { messageFeedbackApi: '訊息反饋(點贊)', messageFeedbackApiTip: '代表終端使用者對返回訊息進行評價,可以點贊與點踩,該資料將在“日誌與標註”頁中可見,並用於後續的模型微調。', messageIDTip: '訊息 ID', - ratingTip: 'like 或 dislike, 空值為撤銷', + ratingTip: 'like 或 dislike,空值為撤銷', chatMsgHistoryApi: '獲取會話歷史訊息', chatMsgHistoryApiTip: '滾動載入形式返回歷史聊天記錄,第一頁返回最新 `limit` 條,即:倒序返回。', chatMsgHistoryConversationIdTip: '會話 ID', diff --git a/web/i18n/zh-Hant/app-debug.ts b/web/i18n/zh-Hant/app-debug.ts index ad29195cb5..7a1cc88ea2 100644 --- a/web/i18n/zh-Hant/app-debug.ts +++ b/web/i18n/zh-Hant/app-debug.ts @@ -123,7 +123,7 @@ const translation = { ok: '好的', contextVarNotEmpty: '上下文查詢變數不能為空', deleteContextVarTitle: '刪除變數“{{varName}}”?', - deleteContextVarTip: '該變數已被設定為上下文查詢變數,刪除該變數將影響知識庫的正常使用。 如果您仍需要刪除它,請在上下文部分中重新選擇它。', + deleteContextVarTip: '該變數已被設定為上下文查詢變數,刪除該變數將影響知識庫的正常使用。如果您仍需要刪除它,請在上下文部分中重新選擇它。', }, }, tools: { @@ -279,9 +279,9 @@ const translation = { visionSettings: { title: '視覺設定', resolution: '解析度', - resolutionTooltip: `低解析度模式將使模型接收影象的低解析度版本,尺寸為512 x 512,並使用65 Tokens 來表示影象。這樣可以使API更快地返回響應,並在不需要高細節的用例中消耗更少的輸入。 + resolutionTooltip: `低解析度模式將使模型接收影象的低解析度版本,尺寸為 512 x 512,並使用 65 Tokens 來表示影象。這樣可以使 API 更快地返回響應,並在不需要高細節的用例中消耗更少的輸入。 \n - 高解析度模式將首先允許模型檢視低解析度影象,然後根據輸入影象的大小建立512畫素的詳細裁剪影象。每個詳細裁剪影象使用兩倍的預算總共為129 Tokens。`, + 高解析度模式將首先允許模型檢視低解析度影象,然後根據輸入影象的大小建立 512 畫素的詳細裁剪影象。每個詳細裁剪影象使用兩倍的預算總共為 129 Tokens。`, high: '高', low: '低', uploadMethod: '上傳方式', @@ -314,7 +314,7 @@ const translation = { openingQuestion: '開場問題', noDataPlaceHolder: '在對話型應用中,讓 AI 主動說第一段話可以拉近與使用者間的距離。', - varTip: '你可以使用變數, 試試輸入 {{variable}}', + varTip: '你可以使用變數,試試輸入 {{variable}}', tooShort: '對話前提示詞至少 20 字才能生成開場白', notIncludeKey: '字首提示詞中不包含變數 {{key}}。請在字首提示詞中新增該變數', }, @@ -342,9 +342,9 @@ const translation = { result: '結果', datasetConfig: { settingTitle: '召回設定', - knowledgeTip: '點選 “+” 按鈕新增知識庫', + knowledgeTip: '點選“+”按鈕新增知識庫', retrieveOneWay: { - title: 'N選1召回', + title: 'N 選 1 召回', description: '根據使用者意圖和知識庫描述,由 Agent 自主判斷選擇最匹配的單個知識庫來查詢相關文字,適合知識庫區分度大且知識庫數量偏少的應用。', }, retrieveMultiWay: { diff --git a/web/i18n/zh-Hant/app-overview.ts b/web/i18n/zh-Hant/app-overview.ts index 2537e0d4c7..21d9247361 100644 --- a/web/i18n/zh-Hant/app-overview.ts +++ b/web/i18n/zh-Hant/app-overview.ts @@ -1,6 +1,6 @@ const translation = { welcome: { - firstStepTip: '開始之前,', + firstStepTip: '開始之前,', enterKeyTip: '請先在下方輸入你的 OpenAI API Key', getKeyTip: '從 OpenAI 獲取你的 API Key', placeholder: '你的 OpenAI API Key(例如 sk-xxxx)', @@ -9,11 +9,11 @@ const translation = { cloud: { trial: { title: '您正在使用 {{providerName}} 的試用配額。', - description: '試用配額僅供您測試使用。 在試用配額用完之前,請自行設定模型提供商或購買額外配額。', + description: '試用配額僅供您測試使用。在試用配額用完之前,請自行設定模型提供商或購買額外配額。', }, exhausted: { - title: '您的試用額度已用完,請設定您的APIKey。', - description: '您的試用配額已用完。 請設定您自己的模型提供商或購買額外配額。', + title: '您的試用額度已用完,請設定您的 APIKey。', + description: '您的試用配額已用完。請設定您自己的模型提供商或購買額外配額。', }, }, selfHost: { @@ -136,11 +136,11 @@ const translation = { }, activeUsers: { title: '活躍使用者數', - explanation: '每日AI互動次數。', + explanation: '每日 AI 互動次數。', }, totalConversations: { title: '總對話數', - explanation: '每日AI對話次數;不包括提示工程/調試。', + explanation: '每日 AI 對話次數;不包括提示工程/調試。', }, tokenUsage: { title: '費用消耗', diff --git a/web/i18n/zh-Hant/app.ts b/web/i18n/zh-Hant/app.ts index f4135d3e73..c393fc949e 100644 --- a/web/i18n/zh-Hant/app.ts +++ b/web/i18n/zh-Hant/app.ts @@ -15,7 +15,7 @@ const translation = { exportFailed: '匯出 DSL 失敗', importDSL: '匯入 DSL 檔案', createFromConfigFile: '透過 DSL 檔案建立', - deleteAppConfirmTitle: '確認刪除應用?', + deleteAppConfirmTitle: '確認刪除應用?', deleteAppConfirmContent: '刪除應用將無法復原。使用者將無法存取你的應用,所有 Prompt 設定和日誌都將一併被刪除。', appDeleted: '應用已刪除', @@ -30,17 +30,17 @@ const translation = { chatbotDescription: '使用大型語言模型構建聊天助手', completionDescription: '構建一個根據提示生成高品質文字的應用程式,例如生成文章、摘要、翻譯等。', completionWarning: '該類型不久後將不再支援建立', - agentDescription: '構建一個智慧Agent,可以自主選擇工具來完成任務', - workflowDescription: '以工作流的形式編排生成型應用,提供更多的自訂設定。 它適合有經驗的使用者。', + agentDescription: '構建一個智慧 Agent,可以自主選擇工具來完成任務', + workflowDescription: '以工作流的形式編排生成型應用,提供更多的自訂設定。它適合有經驗的使用者。', workflowWarning: '正在進行 Beta 測試', chatbotType: '聊天助手編排方法', basic: '基礎編排', basicTip: '新手適用,可以切換成工作流編排', basicFor: '新手適用', - basicDescription: '基本編排允許使用簡單的設定編排聊天機器人應用程式,而無需修改內建提示。 它適合初學者。', + basicDescription: '基本編排允許使用簡單的設定編排聊天機器人應用程式,而無需修改內建提示。它適合初學者。', advanced: '工作流編排', advancedFor: '進階使用者適用', - advancedDescription: '工作流編排以工作流的形式編排聊天機器人,提供自訂設定,包括編輯內建提示的能力。 它適合有經驗的使用者。', + advancedDescription: '工作流編排以工作流的形式編排聊天機器人,提供自訂設定,包括編輯內建提示的能力。它適合有經驗的使用者。', captionName: '應用名稱 & 圖示', appNamePlaceholder: '給你的應用起個名字', captionDescription: '描述', @@ -120,7 +120,7 @@ const translation = { }, tracing: { title: '追蹤應用程式效能', - description: '配置第三方LLMOps提供商並追蹤應用程式效能。', + description: '配置第三方 LLMOps 提供商並追蹤應用程式效能。', config: '配置', view: '查看', collapse: '收起', @@ -129,7 +129,7 @@ const translation = { disabled: '已禁用', disabledTip: '請先配置提供商', enabled: '服務中', - tracingDescription: '捕獲應用程式執行的完整上下文,包括LLM調用、上下文、提示、HTTP請求等,到第三方追蹤平台。', + tracingDescription: '捕獲應用程式執行的完整上下文,包括 LLM 調用、上下文、提示、HTTP 請求等,到第三方追蹤平台。', configProviderTitle: { configured: '已配置', notConfigured: '配置提供商以啟用追蹤', @@ -137,11 +137,11 @@ const translation = { }, langsmith: { title: 'LangSmith', - description: '一個全方位的開發者平台,用於LLM驅動的應用程式生命週期的每個步驟。', + description: '一個全方位的開發者平台,用於 LLM 驅動的應用程式生命週期的每個步驟。', }, langfuse: { title: 'Langfuse', - description: '追蹤、評估、提示管理和指標,用於調試和改進您的LLM應用程式。', + description: '追蹤、評估、提示管理和指標,用於調試和改進您的 LLM 應用程式。', }, inUse: '使用中', configProvider: { @@ -198,7 +198,7 @@ const translation = { label: '應用程式', }, structOutput: { - moreFillTip: '顯示最多10層的嵌套', + moreFillTip: '顯示最多 10 層的嵌套', required: '必需的', LLMResponse: 'LLM 回應', structured: '結構化的', diff --git a/web/i18n/zh-Hant/billing.ts b/web/i18n/zh-Hant/billing.ts index f3ce5ec79c..6ede2c6213 100644 --- a/web/i18n/zh-Hant/billing.ts +++ b/web/i18n/zh-Hant/billing.ts @@ -9,7 +9,7 @@ const translation = { buyPermissionDeniedTip: '請聯絡企業管理員訂閱', plansCommon: { title: '選擇適合您的套餐', - yearlyTip: '訂閱年度計劃可免費獲得 2個月!', + yearlyTip: '訂閱年度計劃可免費獲得 2 個月!', mostPopular: '最受歡迎', planRange: { monthly: '按月', @@ -31,7 +31,7 @@ const translation = { buildApps: '構建應用程式數', vectorSpace: '向量空間', vectorSpaceTooltip: '向量空間是 LLMs 理解您的資料所需的長期記憶系統。', - vectorSpaceBillingTooltip: '向量儲存是將知識庫向量化處理後為讓 LLMs 理解資料而使用的長期記憶儲存,1MB 大約能滿足1.2 million character 的向量化後資料儲存(以 OpenAI Embedding 模型估算,不同模型計算方式有差異)。在向量化過程中,實際的壓縮或尺寸減小取決於內容的複雜性和冗餘性。', + vectorSpaceBillingTooltip: '向量儲存是將知識庫向量化處理後為讓 LLMs 理解資料而使用的長期記憶儲存,1MB 大約能滿足 1.2 million character 的向量化後資料儲存(以 OpenAI Embedding 模型估算,不同模型計算方式有差異)。在向量化過程中,實際的壓縮或尺寸減小取決於內容的複雜性和冗餘性。', documentsUploadQuota: '文件上傳配額', documentProcessingPriority: '文件處理優先順序', documentProcessingPriorityTip: '如需更高的文件處理優先順序,請升級您的套餐', @@ -88,7 +88,7 @@ const translation = { priceTip: '每個工作區/', cloud: '雲服務', documentsRequestQuota: '{{count,number}}/分鐘 知識請求速率限制', - unlimitedApiRate: '沒有API速率限制', + unlimitedApiRate: '沒有 API 速率限制', apiRateLimitTooltip: 'API 使用次數限制適用於通過 Dify API 所做的所有請求,包括文本生成、聊天對話、工作流執行和文檔處理。', getStarted: '開始使用', freeTrialTip: '200 次 OpenAI 通話的免費試用。', @@ -97,12 +97,12 @@ const translation = { apiRateLimit: 'API 限速', teamMember_other: '{{count,number}} 團隊成員', documentsTooltip: '從知識數據來源導入的文件數量配額。', - documentsRequestQuotaTooltip: '指定工作區在知識基礎中每分鐘可以執行的總操作次數,包括數據集的創建、刪除、更新、文檔上傳、修改、歸檔和知識基礎查詢。這個指標用於評估知識基礎請求的性能。例如,如果一個沙箱用戶在一分鐘內連續執行10次命中測試,他們的工作區將在接下來的一分鐘內暫時禁止執行以下操作:數據集的創建、刪除、更新以及文檔上傳或修改。', + documentsRequestQuotaTooltip: '指定工作區在知識基礎中每分鐘可以執行的總操作次數,包括數據集的創建、刪除、更新、文檔上傳、修改、歸檔和知識基礎查詢。這個指標用於評估知識基礎請求的性能。例如,如果一個沙箱用戶在一分鐘內連續執行 10 次命中測試,他們的工作區將在接下來的一分鐘內暫時禁止執行以下操作:數據集的創建、刪除、更新以及文檔上傳或修改。', }, plans: { sandbox: { name: 'Sandbox', - description: '200次 GPT 免費試用', + description: '200 次 GPT 免費試用', includesTitle: '包括:', for: '核心功能免費試用', }, @@ -159,7 +159,7 @@ const translation = { 3: '優先電子郵件及聊天支持', }, for: '適用於中型組織和團隊', - comingSoon: '微軟Azure與Google Cloud支持即將推出', + comingSoon: '微軟 Azure 與 Google Cloud 支持即將推出', priceTip: '根據雲端市場', btnText: '獲取高級版在', name: '高級', diff --git a/web/i18n/zh-Hant/common.ts b/web/i18n/zh-Hant/common.ts index 08510c286b..296fae9e7e 100644 --- a/web/i18n/zh-Hant/common.ts +++ b/web/i18n/zh-Hant/common.ts @@ -116,7 +116,7 @@ const translation = { '影響常見與罕見詞彙使用。\n值較大時,傾向於生成不常見的詞彙和表達方式。\n值越小,更傾向於使用常見和普遍接受的詞彙或短語。', max_tokens: '單次回覆限制 max_tokens', max_tokensTip: - '用於限制回覆的最大長度,以 token 為單位。\n較大的值可能會限制給提示詞、聊天記錄和知識庫留出的空間。\n建議將其設定在三分之二以下。\ngpt-4-1106-preview、gpt-4-vision-preview 最大長度 (輸入128k,輸出4k)', + '用於限制回覆的最大長度,以 token 為單位。\n較大的值可能會限制給提示詞、聊天記錄和知識庫留出的空間。\n建議將其設定在三分之二以下。\ngpt-4-1106-preview、gpt-4-vision-preview 最大長度 (輸入 128k,輸出 4k)', maxTokenSettingTip: '您設定的最大 tokens 數較大,可能會導致 prompt、使用者問題、知識庫內容沒有 token 空間進行處理,建議設定到 2/3 以下。', setToCurrentModelMaxTokenTip: '最大令牌數更新為當前模型最大的令牌數 {{maxToken}} 的 80%。', stop_sequences: '停止序列 stop_sequences', @@ -142,7 +142,7 @@ const translation = { plugins: '外掛', pluginsTips: '整合第三方外掛或建立與 ChatGPT 相容的 AI 外掛。', datasets: '知識庫', - datasetsTips: '即將到來: 上傳自己的長文字資料,或透過 Webhook 整合自己的資料來源', + datasetsTips: '即將到來:上傳自己的長文字資料,或透過 Webhook 整合自己的資料來源', newApp: '建立應用', newDataset: '建立知識庫', tools: '工具', @@ -205,7 +205,7 @@ const translation = { deleteLabel: '要確認,請在下方輸入您的電子郵件', deletePlaceholder: '請輸入您的電子郵件', verificationLabel: '驗證碼', - verificationPlaceholder: '粘貼6位代碼', + verificationPlaceholder: '粘貼 6 位代碼', permanentlyDeleteButton: '永久刪除帳戶', feedbackTitle: '反饋', feedbackLabel: '告訴我們您刪除帳戶的原因?', @@ -250,7 +250,7 @@ const translation = { disInvite: '取消邀請', deleteMember: '刪除成員', you: '(你)', - setBuilder: 'Set as builder (設置為建構器)', + setBuilder: 'Set as builder(設置為建構器)', datasetOperator: '知識管理員', builder: '建築工人', builderTip: '可以構建和編輯自己的應用程式', @@ -331,7 +331,7 @@ const translation = { }, embeddingModel: { key: 'Embedding 模型', - tip: '設定知識庫文件嵌入處理的預設模型,檢索和匯入知識庫均使用該Embedding模型進行向量化處理,切換後將導致已匯入的知識庫與問題之間的向量維度不一致,從而導致檢索失敗。為避免檢索失敗,請勿隨意切換該模型。', + tip: '設定知識庫文件嵌入處理的預設模型,檢索和匯入知識庫均使用該 Embedding 模型進行向量化處理,切換後將導致已匯入的知識庫與問題之間的向量維度不一致,從而導致檢索失敗。為避免檢索失敗,請勿隨意切換該模型。', required: '請選擇 Embedding 模型', }, speechToTextModel: { @@ -367,7 +367,7 @@ const translation = { buyQuota: '購買額度', priorityUse: '優先使用', removeKey: '刪除 API 金鑰', - tip: '已付費額度將優先考慮。 試用額度將在付費額度用完後使用。', + tip: '已付費額度將優先考慮。試用額度將在付費額度用完後使用。', }, item: { deleteDesc: '{{modelName}} 被用作系統推理模型。刪除後部分功能將無法使用。請確認。', @@ -398,7 +398,7 @@ const translation = { getFreeTokens: '獲得免費 Tokens', priorityUsing: '優先使用', deprecated: '已棄用', - confirmDelete: '確認刪除?', + confirmDelete: '確認刪除?', quotaTip: '剩餘免費額度', loadPresets: '載入預設', parameters: '引數', @@ -408,7 +408,7 @@ const translation = { configLoadBalancing: '配置負載均衡', loadBalancingDescription: '使用多組憑證減輕壓力。', addConfig: '添加配置', - upgradeForLoadBalancing: '升級您的計劃以啟用Load Balancing。', + upgradeForLoadBalancing: '升級您的計劃以啟用 Load Balancing。', apiKey: 'API 金鑰', loadBalancing: '負載均衡', providerManagedDescription: '使用模型提供程式提供的單組憑證。', @@ -631,7 +631,7 @@ const translation = { }, errorMsg: { fieldRequired: '{{field}} 為必填項', - urlError: 'URL應以 http:// 或 https:// 開頭', + urlError: 'URL 應以 http:// 或 https:// 開頭', }, fileUploader: { pasteFileLink: '粘貼文件連結', @@ -644,7 +644,7 @@ const translation = { uploadFromComputerLimit: '上傳文件不能超過 {{size}}', }, license: { - expiring: '將在1天內過期', + expiring: '將在 1 天內過期', expiring_plural: '將在 {{count}} 天后過期', unlimited: '無限制', }, @@ -666,7 +666,7 @@ const translation = { iso27001: 'ISO 27001:2022 認證', }, imageInput: { - supportedFormats: '支援PNG、JPG、JPEG、WEBP和GIF', + supportedFormats: '支援 PNG、JPG、JPEG、WEBP 和 GIF', browse: '瀏覽', dropImageHere: '將您的圖片放在這裡,或', }, diff --git a/web/i18n/zh-Hant/dataset-creation.ts b/web/i18n/zh-Hant/dataset-creation.ts index ca2c410ac6..8955deadc8 100644 --- a/web/i18n/zh-Hant/dataset-creation.ts +++ b/web/i18n/zh-Hant/dataset-creation.ts @@ -103,12 +103,12 @@ const translation = { separatorPlaceholder: '例如換行符(\n)或特定的分隔符(如 "***")', maxLength: '分段最大長度', overlap: '分段重疊長度', - overlapTip: '設定分段之間的重疊長度可以保留分段之間的語義關係,提升召回效果。建議設定為最大分段長度的10%-25%', + overlapTip: '設定分段之間的重疊長度可以保留分段之間的語義關係,提升召回效果。建議設定為最大分段長度的 10%-25%', overlapCheck: '分段重疊長度不能大於分段最大長度', rules: '文字預處理規則', removeExtraSpaces: '替換掉連續的空格、換行符和製表符', removeUrlEmails: '刪除所有 URL 和電子郵件地址', - removeStopwords: '去除停用詞,例如 “a”,“an”,“the” 等', + removeStopwords: '去除停用詞,例如“a”,“an”,“the”等', preview: '預覽', reset: '重置', indexMode: '索引方式', @@ -151,14 +151,14 @@ const translation = { datasetSettingLink: '知識庫設定。', websiteSource: '預處理網站', webpageUnit: '頁面', - separatorTip: '分隔符是用於分隔文字的字元。\\n\\n 和 \\n 是分隔段落和行的常用分隔符。與逗號 (\\n\\n,\\n) 組合使用時,當超過最大區塊長度時,段落將按行分段。您也可以使用自定義的特殊分隔符(例如 ***)。', + separatorTip: '分隔符是用於分隔文字的字元。\\n\\n 和 \\n 是分隔段落和行的常用分隔符。與逗號(\\n\\n,\\n)組合使用時,當超過最大區塊長度時,段落將按行分段。您也可以使用自定義的特殊分隔符(例如 ***)。', maxLengthCheck: '塊最大長度應小於 {{limit}}', general: '常規', previewChunkCount: '{{count}}估計塊數', - useQALanguage: '使用Q&A格式的塊', - qaSwitchHighQualityTipContent: '目前,只有高品質索引方法支援Q&A格式分塊。是否要切換到高品質模式?', + useQALanguage: '使用 Q&A 格式的塊', + qaSwitchHighQualityTipContent: '目前,只有高品質索引方法支援 Q&A 格式分塊。是否要切換到高品質模式?', previewChunk: '預覽資料塊(Preview Chunk)', - fullDocTip: '整個文件用作父塊並直接檢索。請注意,出於性能原因,超過10000個令牌的文本將被自動截斷。', + fullDocTip: '整個文件用作父塊並直接檢索。請注意,出於性能原因,超過 10000 個令牌的文本將被自動截斷。', parentChunkForContext: '父母的背景', previewChunkTip: '點擊左側的 『Preview Chunk』 按鈕載入預覽', parentChild: '父子', @@ -166,7 +166,7 @@ const translation = { parentChildChunkDelimiterTip: '分隔符是用於分隔文字的字元。建議使用 \\n 將父塊拆分為小的子塊。您還可以使用自己定義的特殊分隔符。', parentChildDelimiterTip: '分隔符是用於分隔文字的字元。建議將原始文檔拆分為多個大型父塊。您還可以使用自己定義的特殊分隔符。', generalTip: '常規文本分塊模式,檢索和調用的塊是相同的。', - highQualityTip: '在 High Quality 模式下完成嵌入後,將無法恢復到 Economical (經濟) 模式。', + highQualityTip: '在 High Quality 模式下完成嵌入後,將無法恢復到 Economical(經濟)模式。', childChunkForRetrieval: '用於檢索的 Child-chunk', paragraphTip: '此模式根據分隔符和最大區塊長度將文本拆分為段落,使用拆分文本作為父區塊進行檢索。', paragraph: '段', diff --git a/web/i18n/zh-Hant/dataset-documents.ts b/web/i18n/zh-Hant/dataset-documents.ts index 5ad2c8f61f..60b1df80f3 100644 --- a/web/i18n/zh-Hant/dataset-documents.ts +++ b/web/i18n/zh-Hant/dataset-documents.ts @@ -355,7 +355,7 @@ const translation = { addChunk: '添加數據塊', addChildChunk: '添加子塊', addAnother: '添加另一個', - childChunkAdded: '添加了1個子塊', + childChunkAdded: '添加了 1 個子塊', editParentChunk: '編輯父塊(Edit Parent Chunk)', editChildChunk: '編輯子塊', chunkDetail: '數據塊詳細資訊', diff --git a/web/i18n/zh-Hant/dataset-settings.ts b/web/i18n/zh-Hant/dataset-settings.ts index 3dce646e7e..9068706762 100644 --- a/web/i18n/zh-Hant/dataset-settings.ts +++ b/web/i18n/zh-Hant/dataset-settings.ts @@ -30,7 +30,7 @@ const translation = { save: '儲存', permissionsInvitedMembers: '部分團隊成員', me: '(您)', - externalKnowledgeID: '外部知識ID', + externalKnowledgeID: '外部知識 ID', externalKnowledgeAPI: '外部知識 API', retrievalSettings: '檢索設置', indexMethodChangeToEconomyDisabledTip: '不適用於從 HQ 降級到 ECO', diff --git a/web/i18n/zh-Hant/dataset.ts b/web/i18n/zh-Hant/dataset.ts index ce4d63a54b..0a6b015155 100644 --- a/web/i18n/zh-Hant/dataset.ts +++ b/web/i18n/zh-Hant/dataset.ts @@ -7,7 +7,7 @@ const translation = { createDatasetIntro: '匯入您自己的文字資料或透過 Webhook 實時寫入資料以增強 LLM 的上下文。', deleteDatasetConfirmTitle: '要刪除知識庫嗎?', deleteDatasetConfirmContent: - '刪除知識庫是不可逆的。使用者將無法再訪問您的知識庫,所有的提示配置和日誌將被永久刪除。', + '刪除知識庫是不可逆的。使用者將無法再訪問您的知識庫,所有的提示配置和日誌將被永久刪除。', datasetUsedByApp: '這些知識正被一些應用程序使用。應用程序將無法再使用這些知識,所有提示配置和日誌將被永久刪除。', datasetDeleted: '知識庫已刪除', datasetDeleteFailed: '刪除知識庫失敗', @@ -68,9 +68,9 @@ const translation = { semantic: '語義', keyword: '關鍵詞', }, - nTo1RetrievalLegacy: 'N對1檢索將從9月起正式棄用。建議使用最新的多路徑檢索以獲得更好的結果。', + nTo1RetrievalLegacy: 'N 對 1 檢索將從 9 月起正式棄用。建議使用最新的多路徑檢索以獲得更好的結果。', nTo1RetrievalLegacyLink: '了解更多', - nTo1RetrievalLegacyLinkText: 'N對1檢索將於9月正式棄用。', + nTo1RetrievalLegacyLinkText: 'N 對 1 檢索將於 9 月正式棄用。', defaultRetrievalTip: '默認情況下,使用多路徑檢索。從多個知識庫中檢索知識,然後重新排名。', editExternalAPIConfirmWarningContent: { end: 'external knowledge,並且此修改將應用於所有這些 Knowledge。是否確實要保存此更改?', @@ -98,7 +98,7 @@ const translation = { content: { link: '瞭解如何創建外部 API', front: '要連接到外部知識庫,您需要先創建外部 API。請仔細閱讀並參考', - end: '.然後找到對應的知識ID並在左側的表單中填寫。如果資訊全部正確,點擊連接按鈕后,會自動跳轉到知識庫中的檢索測試。', + end: '.然後找到對應的知識 ID 並在左側的表單中填寫。如果資訊全部正確,點擊連接按鈕后,會自動跳轉到知識庫中的檢索測試。', }, title: '如何連接到外部知識庫', learnMore: '瞭解更多資訊', @@ -138,7 +138,7 @@ const translation = { allExternalTip: '僅使用外部知識時,用戶可以選擇是否啟用 Rerank 模型。如果未啟用,則檢索到的數據塊將根據分數進行排序。當不同知識庫的檢索策略不一致時,就會不準確。', externalKnowledgeIdPlaceholder: '請輸入 Knowledge ID', editExternalAPIFormTitle: '編輯外部知識 API', - externalKnowledgeId: '外部知識ID', + externalKnowledgeId: '外部知識 ID', externalAPIPanelDescription: '外部知識 API 用於連接到 Dify 外部的知識庫,並從該知識庫中檢索知識。', externalAPI: '外部 API', editExternalAPITooltipTitle: '關聯知識', diff --git a/web/i18n/zh-Hant/education.ts b/web/i18n/zh-Hant/education.ts index 9637324b85..8efc70f4d6 100644 --- a/web/i18n/zh-Hant/education.ts +++ b/web/i18n/zh-Hant/education.ts @@ -26,14 +26,14 @@ const translation = { end: '透過提交:', }, option: { - age: '我確認我至少18歲', + age: '我確認我至少 18 歲', inSchool: '我確認我已在所提供的機構註冊或受僱。Dify 可能會要求提供註冊/就業的證明。如果我錯誤表述我的資格,我同意支付根據我的教育狀況最初免除的任何費用。', }, title: '條款與協議', }, }, - rejectContent: '不幸的是,您不符合教育驗證狀態,因此如果您使用此電子郵件地址,將無法獲得Dify專業計劃的100%獨家優惠券。', - successContent: '我們已經向您的帳戶發放了Dify專業計劃的100%折扣優惠券。該優惠券有效期為一年,請在有效期內使用它。', + rejectContent: '不幸的是,您不符合教育驗證狀態,因此如果您使用此電子郵件地址,將無法獲得 Dify 專業計劃的 100% 獨家優惠券。', + successContent: '我們已經向您的帳戶發放了 Dify 專業計劃的 100% 折扣優惠券。該優惠券有效期為一年,請在有效期內使用它。', learn: '了解如何進行教育驗證', rejectTitle: '您的 Dify 教育驗證已被拒絕', submitError: '表單提交失敗。請稍後再試。', diff --git a/web/i18n/zh-Hant/login.ts b/web/i18n/zh-Hant/login.ts index ada0e1bf89..a928b3b800 100644 --- a/web/i18n/zh-Hant/login.ts +++ b/web/i18n/zh-Hant/login.ts @@ -52,12 +52,12 @@ const translation = { emailInValid: '請輸入有效的郵箱地址', nameEmpty: '使用者名稱不能為空', passwordEmpty: '密碼不能為空', - passwordInvalid: '密碼必須包含字母和數字,且長度不小於8位', - passwordLengthInValid: '密碼必須至少為8個字元', + passwordInvalid: '密碼必須包含字母和數字,且長度不小於 8 位', + passwordLengthInValid: '密碼必須至少為 8 個字元', registrationNotAllowed: '找不到帳戶。請聯繫系統管理員進行註冊。', }, license: { - tip: '啟動 Dify 社群版之前, 請閱讀 GitHub 上的', + tip: '啟動 Dify 社群版之前,請閱讀 GitHub 上的', link: '開源協議', }, join: '加入', @@ -78,7 +78,7 @@ const translation = { emptyCode: '驗證碼是必需的', checkYourEmail: '檢查您的電子郵件', tips: '我們將驗證碼發送到 {{email}}', - verificationCodePlaceholder: '輸入6位代碼', + verificationCodePlaceholder: '輸入 6 位代碼', useAnotherMethod: '使用其他方法', validTime: '請記住,該代碼的有效期為 5 分鐘', verificationCode: '驗證碼', diff --git a/web/i18n/zh-Hant/plugin.ts b/web/i18n/zh-Hant/plugin.ts index 3b9040dc91..4d4e6acf2e 100644 --- a/web/i18n/zh-Hant/plugin.ts +++ b/web/i18n/zh-Hant/plugin.ts @@ -26,7 +26,7 @@ const translation = { source: { marketplace: '市場', local: '本地包檔', - github: 'GitHub的', + github: 'GitHub 的', }, detailPanel: { categoryTip: { @@ -45,7 +45,7 @@ const translation = { checkUpdate: '檢查更新', }, toolSelector: { - uninstalledContent: '此外掛程式是從local/GitHub儲存庫安裝的。請在安裝後使用。', + uninstalledContent: '此外掛程式是從 local/GitHub 儲存庫安裝的。請在安裝後使用。', descriptionLabel: '工具描述', params: '推理配置', paramsTip2: '當 \'Automatic\' 關閉時,使用預設值。', @@ -181,7 +181,7 @@ const translation = { viewMore: '查看更多', difyMarketplace: 'Dify 市場', pluginsResult: '{{num}} 個結果', - verifiedTip: '由Dify驗證', + verifiedTip: '由 Dify 驗證', partnerTip: '由 Dify 合作夥伴驗證', }, task: { diff --git a/web/i18n/zh-Hant/share-app.ts b/web/i18n/zh-Hant/share-app.ts index bf81582d58..54d2ff98b6 100644 --- a/web/i18n/zh-Hant/share-app.ts +++ b/web/i18n/zh-Hant/share-app.ts @@ -66,8 +66,8 @@ const translation = { empty: '上傳檔案的內容不能為空', fileStructNotMatch: '上傳檔案的內容與結構不匹配', emptyLine: '第 {{rowIndex}} 行的內容為空', - invalidLine: '第 {{rowIndex}} 行: {{varName}}值必填', - moreThanMaxLengthLine: '第 {{rowIndex}} 行: {{varName}}值超過最大長度 {{maxLength}}', + invalidLine: '第 {{rowIndex}} 行:{{varName}}值必填', + moreThanMaxLengthLine: '第 {{rowIndex}} 行:{{varName}}值超過最大長度 {{maxLength}}', atLeastOne: '上傳檔案的內容不能少於一條', }, execution: '執行', diff --git a/web/i18n/zh-Hant/tools.ts b/web/i18n/zh-Hant/tools.ts index 5669e87cb3..6e5a95f2a5 100644 --- a/web/i18n/zh-Hant/tools.ts +++ b/web/i18n/zh-Hant/tools.ts @@ -35,8 +35,8 @@ const translation = { urlError: '請輸入有效的 URL', examples: '例子', exampleOptions: { - json: '天氣(JSON)', - yaml: '寵物商店(YAML)', + json: '天氣 (JSON)', + yaml: '寵物商店 (YAML)', blankTemplate: '空白模版', }, availableTools: { @@ -91,7 +91,7 @@ const translation = { }, description: '描述', nameForToolCall: '工具調用名稱', - confirmTitle: '確認儲存 ?', + confirmTitle: '確認儲存?', descriptionPlaceholder: '工具用途的簡要描述,例如,獲取特定位置的溫度。', nameForToolCallTip: '僅支援數位、字母和下劃線。', confirmTip: '使用此工具的應用程式將受到影響', @@ -123,7 +123,7 @@ const translation = { file: '檔', }, noCustomTool: { - title: '沒有自定義工具!', + title: '沒有自定義工具!', content: '在此統一新增和管理你的自定義工具,方便構建應用時使用。', createTool: '建立工具', }, diff --git a/web/i18n/zh-Hant/workflow.ts b/web/i18n/zh-Hant/workflow.ts index e3d4d8360d..79f164f0f0 100644 --- a/web/i18n/zh-Hant/workflow.ts +++ b/web/i18n/zh-Hant/workflow.ts @@ -51,7 +51,7 @@ const translation = { processData: '數據處理', input: '輸入', output: '輸出', - jinjaEditorPlaceholder: '輸入 “/” 或 “{” 插入變量', + jinjaEditorPlaceholder: '輸入“/”或“{”插入變量', viewOnly: '只讀', showRunHistory: '顯示運行歷史', enableJinja: '開啟支持 Jinja 模板', @@ -73,7 +73,7 @@ const translation = { backupCurrentDraft: 'Backup Current Draft', overwriteAndImport: '覆蓋和導入', importSuccess: '導入成功', - chooseDSL: '選擇 DSL(yml) 檔', + chooseDSL: '選擇 DSL(yml)檔', syncingData: '同步數據,只需幾秒鐘。', importDSLTip: '當前草稿將被覆蓋。在導入之前將工作流匯出為備份。', importFailure: '匯入失敗', @@ -108,17 +108,17 @@ const translation = { noHistory: '無歷史記錄', publishUpdate: '發布更新', referenceVar: '參考變量', - exportSVG: '匯出為SVG', + exportSVG: '匯出為 SVG', exportPNG: '匯出為 PNG', noExist: '沒有這個變數', versionHistory: '版本歷史', exitVersions: '退出版本', exportImage: '匯出圖像', - exportJPEG: '匯出為JPEG', + exportJPEG: '匯出為 JPEG', }, env: { envPanelTitle: '環境變數', - envDescription: '環境變數可用於存儲私人信息和憑證。它們是唯讀的,並且可以在導出時與DSL文件分開。', + envDescription: '環境變數可用於存儲私人信息和憑證。它們是唯讀的,並且可以在導出時與 DSL 文件分開。', envPanelButton: '添加變數', modal: { title: '添加環境變數', @@ -128,13 +128,13 @@ const translation = { namePlaceholder: '環境名稱', value: '值', valuePlaceholder: '環境值', - secretTip: '用於定義敏感信息或數據,DSL設置配置為防止洩露。', + secretTip: '用於定義敏感信息或數據,DSL 設置配置為防止洩露。', }, export: { title: '導出機密環境變數?', checkbox: '導出機密值', - ignore: '導出DSL', - export: '導出帶有機密值的DSL', + ignore: '導出 DSL', + export: '導出帶有機密值的 DSL', }, }, chatVariable: { @@ -204,7 +204,7 @@ const translation = { }, invalidVariable: '無效的變量', rerankModelRequired: '在開啟 Rerank 模型之前,請在設置中確認模型配置成功。', - toolParameterRequired: '{{field}}: 参數 [{{param}}] 為必填項', + toolParameterRequired: '{{field}}:参數 [{{param}}] 為必填項', noValidTool: '{{field}} 未選擇有效工具', }, singleRun: { @@ -336,9 +336,9 @@ const translation = { failBranch: { title: '失敗分支', desc: '當發生錯誤時,它會執行 exception 分支', - customize: '轉到畫布以自定義fail分支邏輯。', - inLog: 'Node 異常,將自動執行fail分支。節點輸出將返回錯誤類型和錯誤消息,並將其傳遞給下游。', - customizeTip: '啟動fail分支後,節點引發的異常不會終止進程。相反,它將自動執行預定義的fail分支,允許您靈活地提供錯誤消息、報告、修復或跳過操作。', + customize: '轉到畫布以自定義 fail 分支邏輯。', + inLog: 'Node 異常,將自動執行 fail 分支。節點輸出將返回錯誤類型和錯誤消息,並將其傳遞給下游。', + customizeTip: '啟動 fail 分支後,節點引發的異常不會終止進程。相反,它將自動執行預定義的 fail 分支,允許您靈活地提供錯誤消息、報告、修復或跳過操作。', }, partialSucceeded: { tip: '進程中有 {{num}} 個節點運行異常,請前往 tracing 查看日誌。', @@ -436,7 +436,7 @@ const translation = { import: '從 JSON 匯入', generatedResult: '生成的結果', generateJsonSchema: '生成 JSON 架構', - promptTooltip: '將文本描述轉換成標準化的 JSON Schema結構。', + promptTooltip: '將文本描述轉換成標準化的 JSON Schema 結構。', doc: '了解更多有關結構化輸出的資訊', addChildField: '新增子欄位', title: '結構化輸出模式', @@ -643,7 +643,7 @@ const translation = { 'variables': '變數', 'selectAssignedVariable': '選擇配置的變數...', 'setParameter': '設定參數...', - 'noVarTip': '點擊 「+」 按鈕添加變數', + 'noVarTip': '點擊「+」按鈕添加變數', 'assignedVarsDescription': '分配的變數必須是可寫變數,例如對話變數。', 'varNotSet': '未設置變數', }, @@ -657,9 +657,9 @@ const translation = { type: '支持類型。現在只支持圖片', transfer_method: '傳輸方式。值為 remote_url 或 local_file', url: '圖片鏈接', - upload_file_id: '上傳文件ID', + upload_file_id: '上傳文件 ID', }, - json: '工具生成的JSON', + json: '工具生成的 JSON', }, }, questionClassifiers: { @@ -762,13 +762,13 @@ const translation = { result: '篩選結果', }, desc: '描述', - asc: 'ASC的', + asc: 'ASC 的', orderBy: '排序依據', inputVar: '輸入變數', filterConditionComparisonValue: 'Filter Condition 值', filterCondition: '篩選條件', limit: '前 N 名', - selectVariableKeyPlaceholder: 'Select sub variable key (選擇子變數鍵)', + selectVariableKeyPlaceholder: 'Select sub variable key(選擇子變數鍵)', filterConditionComparisonOperator: 'Filter Condition Comparison 運算符', filterConditionKey: '篩選條件鍵', extractsCondition: '提取第 N 項', @@ -806,7 +806,7 @@ const translation = { transfer_method: '轉移方法。值為 remote_url 或 local_file', title: '代理生成的檔', url: '圖片網址', - upload_file_id: '上傳檔ID', + upload_file_id: '上傳檔 ID', }, text: '代理生成的內容', json: '代理生成的 JSON', From 006496f24ec1ff06ea9928fa8902905e070a5323 Mon Sep 17 00:00:00 2001 From: Abdullah AlOsaimi <189027247+osaimi@users.noreply.github.com> Date: Wed, 4 Jun 2025 09:19:35 +0300 Subject: [PATCH 52/73] raise error when process_rule is required but missing (#20599) --- api/controllers/service_api/dataset/document.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/controllers/service_api/dataset/document.py b/api/controllers/service_api/dataset/document.py index 418363ffbb..ea8a9f0f41 100644 --- a/api/controllers/service_api/dataset/document.py +++ b/api/controllers/service_api/dataset/document.py @@ -206,12 +206,16 @@ class DocumentAddByFileApi(DatasetApiResource): knowledge_config = KnowledgeConfig(**args) DocumentService.document_create_args_validate(knowledge_config) + dataset_process_rule = dataset.latest_process_rule if "process_rule" not in args else None + if not knowledge_config.original_document_id and not dataset_process_rule and not knowledge_config.process_rule: + raise ValueError("process_rule is required.") + try: documents, batch = DocumentService.save_document_with_dataset_id( dataset=dataset, knowledge_config=knowledge_config, account=dataset.created_by_account, - dataset_process_rule=dataset.latest_process_rule if "process_rule" not in args else None, + dataset_process_rule=dataset_process_rule, created_from="api", ) except ProviderTokenNotInitError as ex: From d22c351221522ed095d02636ac0f7f5aa1286524 Mon Sep 17 00:00:00 2001 From: Joel Date: Wed, 4 Jun 2025 15:56:29 +0800 Subject: [PATCH 53/73] chore: fix some security issues in markdown (#20639) --- .../components/base/markdown-blocks/button.tsx | 16 ++++------------ web/app/components/base/markdown-blocks/link.tsx | 7 ++++++- web/app/components/base/markdown-blocks/utils.ts | 3 +++ 3 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 web/app/components/base/markdown-blocks/utils.ts diff --git a/web/app/components/base/markdown-blocks/button.tsx b/web/app/components/base/markdown-blocks/button.tsx index 81a3f30660..4646b12921 100644 --- a/web/app/components/base/markdown-blocks/button.tsx +++ b/web/app/components/base/markdown-blocks/button.tsx @@ -1,7 +1,7 @@ import { useChatContext } from '@/app/components/base/chat/chat/context' import Button from '@/app/components/base/button' import cn from '@/utils/classnames' - +import { isValidUrl } from './utils' const MarkdownButton = ({ node }: any) => { const { onSend } = useChatContext() const variant = node.properties.dataVariant @@ -9,25 +9,17 @@ const MarkdownButton = ({ node }: any) => { const link = node.properties.dataLink const size = node.properties.dataSize - function is_valid_url(url: string): boolean { - try { - const parsed_url = new URL(url) - return ['http:', 'https:'].includes(parsed_url.protocol) - } - catch { - return false - } - } - return + + +
+
+
+
router.back()} className='flex h-9 cursor-pointer items-center justify-center text-text-tertiary'> +
+ +
+ {t('login.back')} +
+ +} diff --git a/web/app/(shareLayout)/webapp-reset-password/layout.tsx b/web/app/(shareLayout)/webapp-reset-password/layout.tsx new file mode 100644 index 0000000000..e0ac6b9ad6 --- /dev/null +++ b/web/app/(shareLayout)/webapp-reset-password/layout.tsx @@ -0,0 +1,30 @@ +'use client' +import Header from '@/app/signin/_header' + +import cn from '@/utils/classnames' +import { useGlobalPublicStore } from '@/context/global-public-context' + +export default function SignInLayout({ children }: any) { + const { systemFeatures } = useGlobalPublicStore() + return <> +
+
+
+
+
+ {children} +
+
+ {!systemFeatures.branding.enabled &&
+ © {new Date().getFullYear()} LangGenius, Inc. All rights reserved. +
} +
+
+ +} diff --git a/web/app/(shareLayout)/webapp-reset-password/page.tsx b/web/app/(shareLayout)/webapp-reset-password/page.tsx new file mode 100644 index 0000000000..96cd4c5805 --- /dev/null +++ b/web/app/(shareLayout)/webapp-reset-password/page.tsx @@ -0,0 +1,104 @@ +'use client' +import Link from 'next/link' +import { RiArrowLeftLine, RiLockPasswordLine } from '@remixicon/react' +import { useTranslation } from 'react-i18next' +import { useState } from 'react' +import { useRouter, useSearchParams } from 'next/navigation' +import { useContext } from 'use-context-selector' +import { COUNT_DOWN_KEY, COUNT_DOWN_TIME_MS } from '@/app/components/signin/countdown' +import { emailRegex } from '@/config' +import Button from '@/app/components/base/button' +import Input from '@/app/components/base/input' +import Toast from '@/app/components/base/toast' +import { sendResetPasswordCode } from '@/service/common' +import I18NContext from '@/context/i18n' +import { noop } from 'lodash-es' +import useDocumentTitle from '@/hooks/use-document-title' + +export default function CheckCode() { + const { t } = useTranslation() + useDocumentTitle('') + const searchParams = useSearchParams() + const router = useRouter() + const [email, setEmail] = useState('') + const [loading, setIsLoading] = useState(false) + const { locale } = useContext(I18NContext) + + const handleGetEMailVerificationCode = async () => { + try { + if (!email) { + Toast.notify({ type: 'error', message: t('login.error.emailEmpty') }) + return + } + + if (!emailRegex.test(email)) { + Toast.notify({ + type: 'error', + message: t('login.error.emailInValid'), + }) + return + } + setIsLoading(true) + const res = await sendResetPasswordCode(email, locale) + if (res.result === 'success') { + localStorage.setItem(COUNT_DOWN_KEY, `${COUNT_DOWN_TIME_MS}`) + const params = new URLSearchParams(searchParams) + params.set('token', encodeURIComponent(res.data)) + params.set('email', encodeURIComponent(email)) + router.push(`/webapp-reset-password/check-code?${params.toString()}`) + } + else if (res.code === 'account_not_found') { + Toast.notify({ + type: 'error', + message: t('login.error.registrationNotAllowed'), + }) + } + else { + Toast.notify({ + type: 'error', + message: res.data, + }) + } + } + catch (error) { + console.error(error) + } + finally { + setIsLoading(false) + } + } + + return
+
+ +
+
+

{t('login.resetPassword')}

+

+ {t('login.resetPasswordDesc')} +

+
+ +
+ +
+ +
+ setEmail(e.target.value)} /> +
+
+ +
+
+ +
+
+
+ +
+ +
+ {t('login.backToLogin')} + +
+} diff --git a/web/app/(shareLayout)/webapp-reset-password/set-password/page.tsx b/web/app/(shareLayout)/webapp-reset-password/set-password/page.tsx new file mode 100644 index 0000000000..9f9a8ad4e3 --- /dev/null +++ b/web/app/(shareLayout)/webapp-reset-password/set-password/page.tsx @@ -0,0 +1,188 @@ +'use client' +import { useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useRouter, useSearchParams } from 'next/navigation' +import cn from 'classnames' +import { RiCheckboxCircleFill } from '@remixicon/react' +import { useCountDown } from 'ahooks' +import Button from '@/app/components/base/button' +import { changeWebAppPasswordWithToken } from '@/service/common' +import Toast from '@/app/components/base/toast' +import Input from '@/app/components/base/input' + +const validPassword = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/ + +const ChangePasswordForm = () => { + const { t } = useTranslation() + const router = useRouter() + const searchParams = useSearchParams() + const token = decodeURIComponent(searchParams.get('token') || '') + + const [password, setPassword] = useState('') + const [confirmPassword, setConfirmPassword] = useState('') + const [showSuccess, setShowSuccess] = useState(false) + const [showPassword, setShowPassword] = useState(false) + const [showConfirmPassword, setShowConfirmPassword] = useState(false) + + const showErrorMessage = useCallback((message: string) => { + Toast.notify({ + type: 'error', + message, + }) + }, []) + + const getSignInUrl = () => { + return `/webapp-signin?redirect_url=${searchParams.get('redirect_url') || ''}` + } + + const AUTO_REDIRECT_TIME = 5000 + const [leftTime, setLeftTime] = useState(undefined) + const [countdown] = useCountDown({ + leftTime, + onEnd: () => { + router.replace(getSignInUrl()) + }, + }) + + const valid = useCallback(() => { + if (!password.trim()) { + showErrorMessage(t('login.error.passwordEmpty')) + return false + } + if (!validPassword.test(password)) { + showErrorMessage(t('login.error.passwordInvalid')) + return false + } + if (password !== confirmPassword) { + showErrorMessage(t('common.account.notEqual')) + return false + } + return true + }, [password, confirmPassword, showErrorMessage, t]) + + const handleChangePassword = useCallback(async () => { + if (!valid()) + return + try { + await changeWebAppPasswordWithToken({ + url: '/forgot-password/resets', + body: { + token, + new_password: password, + password_confirm: confirmPassword, + }, + }) + setShowSuccess(true) + setLeftTime(AUTO_REDIRECT_TIME) + } + catch (error) { + console.error(error) + } + }, [password, token, valid, confirmPassword]) + + return ( +
+ {!showSuccess && ( +
+
+

+ {t('login.changePassword')} +

+

+ {t('login.changePasswordTip')} +

+
+ +
+
+ {/* Password */} +
+ +
+ setPassword(e.target.value)} + placeholder={t('login.passwordPlaceholder') || ''} + /> + +
+ +
+
+
{t('login.error.passwordInvalid')}
+
+ {/* Confirm Password */} +
+ +
+ setConfirmPassword(e.target.value)} + placeholder={t('login.confirmPasswordPlaceholder') || ''} + /> +
+ +
+
+
+
+ +
+
+
+
+ )} + {showSuccess && ( +
+
+
+ +
+

+ {t('login.passwordChangedTip')} +

+
+
+ +
+
+ )} +
+ ) +} + +export default ChangePasswordForm diff --git a/web/app/(shareLayout)/webapp-signin/check-code/page.tsx b/web/app/(shareLayout)/webapp-signin/check-code/page.tsx new file mode 100644 index 0000000000..1b8f18c98f --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/check-code/page.tsx @@ -0,0 +1,115 @@ +'use client' +import { RiArrowLeftLine, RiMailSendFill } from '@remixicon/react' +import { useTranslation } from 'react-i18next' +import { useCallback, useState } from 'react' +import { useRouter, useSearchParams } from 'next/navigation' +import { useContext } from 'use-context-selector' +import Countdown from '@/app/components/signin/countdown' +import Button from '@/app/components/base/button' +import Input from '@/app/components/base/input' +import Toast from '@/app/components/base/toast' +import { sendWebAppEMailLoginCode, webAppEmailLoginWithCode } from '@/service/common' +import I18NContext from '@/context/i18n' +import { setAccessToken } from '@/app/components/share/utils' +import { fetchAccessToken } from '@/service/share' + +export default function CheckCode() { + const { t } = useTranslation() + const router = useRouter() + const searchParams = useSearchParams() + const email = decodeURIComponent(searchParams.get('email') as string) + const token = decodeURIComponent(searchParams.get('token') as string) + const [code, setVerifyCode] = useState('') + const [loading, setIsLoading] = useState(false) + const { locale } = useContext(I18NContext) + const redirectUrl = searchParams.get('redirect_url') + + const getAppCodeFromRedirectUrl = useCallback(() => { + const appCode = redirectUrl?.split('/').pop() + if (!appCode) + return null + + return appCode + }, [redirectUrl]) + + const verify = async () => { + try { + const appCode = getAppCodeFromRedirectUrl() + if (!code.trim()) { + Toast.notify({ + type: 'error', + message: t('login.checkCode.emptyCode'), + }) + return + } + if (!/\d{6}/.test(code)) { + Toast.notify({ + type: 'error', + message: t('login.checkCode.invalidCode'), + }) + return + } + if (!redirectUrl || !appCode) { + Toast.notify({ + type: 'error', + message: t('login.error.redirectUrlMissing'), + }) + return + } + setIsLoading(true) + const ret = await webAppEmailLoginWithCode({ email, code, token }) + if (ret.result === 'success') { + localStorage.setItem('webapp_access_token', ret.data.access_token) + const tokenResp = await fetchAccessToken({ appCode, webAppAccessToken: ret.data.access_token }) + await setAccessToken(appCode, tokenResp.access_token) + router.replace(redirectUrl) + } + } + catch (error) { console.error(error) } + finally { + setIsLoading(false) + } + } + + const resendCode = async () => { + try { + const ret = await sendWebAppEMailLoginCode(email, locale) + if (ret.result === 'success') { + const params = new URLSearchParams(searchParams) + params.set('token', encodeURIComponent(ret.data)) + router.replace(`/webapp-signin/check-code?${params.toString()}`) + } + } + catch (error) { console.error(error) } + } + + return
+
+ +
+
+

{t('login.checkCode.checkYourEmail')}

+

+ +
+ {t('login.checkCode.validTime')} +

+
+ +
+ + setVerifyCode(e.target.value)} max-length={6} className='mt-1' placeholder={t('login.checkCode.verificationCodePlaceholder') as string} /> + + + +
+
+
+
router.back()} className='flex h-9 cursor-pointer items-center justify-center text-text-tertiary'> +
+ +
+ {t('login.back')} +
+
+} diff --git a/web/app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx b/web/app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx new file mode 100644 index 0000000000..e9b15ae331 --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx @@ -0,0 +1,80 @@ +'use client' +import { useRouter, useSearchParams } from 'next/navigation' +import React, { useCallback, useEffect } from 'react' +import Toast from '@/app/components/base/toast' +import { fetchWebOAuth2SSOUrl, fetchWebOIDCSSOUrl, fetchWebSAMLSSOUrl } from '@/service/share' +import { useGlobalPublicStore } from '@/context/global-public-context' +import { SSOProtocol } from '@/types/feature' +import Loading from '@/app/components/base/loading' +import AppUnavailable from '@/app/components/base/app-unavailable' + +const ExternalMemberSSOAuth = () => { + const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) + const searchParams = useSearchParams() + const router = useRouter() + + const redirectUrl = searchParams.get('redirect_url') + + const showErrorToast = (message: string) => { + Toast.notify({ + type: 'error', + message, + }) + } + + const getAppCodeFromRedirectUrl = useCallback(() => { + const appCode = redirectUrl?.split('/').pop() + if (!appCode) + return null + + return appCode + }, [redirectUrl]) + + const handleSSOLogin = useCallback(async () => { + const appCode = getAppCodeFromRedirectUrl() + if (!appCode || !redirectUrl) { + showErrorToast('redirect url or app code is invalid.') + return + } + + switch (systemFeatures.webapp_auth.sso_config.protocol) { + case SSOProtocol.SAML: { + const samlRes = await fetchWebSAMLSSOUrl(appCode, redirectUrl) + router.push(samlRes.url) + break + } + case SSOProtocol.OIDC: { + const oidcRes = await fetchWebOIDCSSOUrl(appCode, redirectUrl) + router.push(oidcRes.url) + break + } + case SSOProtocol.OAuth2: { + const oauth2Res = await fetchWebOAuth2SSOUrl(appCode, redirectUrl) + router.push(oauth2Res.url) + break + } + case '': + break + default: + showErrorToast('SSO protocol is not supported.') + } + }, [getAppCodeFromRedirectUrl, redirectUrl, router, systemFeatures.webapp_auth.sso_config.protocol]) + + useEffect(() => { + handleSSOLogin() + }, [handleSSOLogin]) + + if (!systemFeatures.webapp_auth.sso_config.protocol) { + return
+ +
+ } + + return ( +
+ +
+ ) +} + +export default React.memo(ExternalMemberSSOAuth) diff --git a/web/app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx b/web/app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx new file mode 100644 index 0000000000..29af3e3a57 --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx @@ -0,0 +1,68 @@ +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useRouter, useSearchParams } from 'next/navigation' +import { useContext } from 'use-context-selector' +import Input from '@/app/components/base/input' +import Button from '@/app/components/base/button' +import { emailRegex } from '@/config' +import Toast from '@/app/components/base/toast' +import { sendWebAppEMailLoginCode } from '@/service/common' +import { COUNT_DOWN_KEY, COUNT_DOWN_TIME_MS } from '@/app/components/signin/countdown' +import I18NContext from '@/context/i18n' +import { noop } from 'lodash-es' + +export default function MailAndCodeAuth() { + const { t } = useTranslation() + const router = useRouter() + const searchParams = useSearchParams() + const emailFromLink = decodeURIComponent(searchParams.get('email') || '') + const [email, setEmail] = useState(emailFromLink) + const [loading, setIsLoading] = useState(false) + const { locale } = useContext(I18NContext) + + const handleGetEMailVerificationCode = async () => { + try { + if (!email) { + Toast.notify({ type: 'error', message: t('login.error.emailEmpty') }) + return + } + + if (!emailRegex.test(email)) { + Toast.notify({ + type: 'error', + message: t('login.error.emailInValid'), + }) + return + } + setIsLoading(true) + const ret = await sendWebAppEMailLoginCode(email, locale) + if (ret.result === 'success') { + localStorage.setItem(COUNT_DOWN_KEY, `${COUNT_DOWN_TIME_MS}`) + const params = new URLSearchParams(searchParams) + params.set('email', encodeURIComponent(email)) + params.set('token', encodeURIComponent(ret.data)) + router.push(`/webapp-signin/check-code?${params.toString()}`) + } + } + catch (error) { + console.error(error) + } + finally { + setIsLoading(false) + } + } + + return (
+ +
+ +
+ setEmail(e.target.value)} /> +
+
+ +
+
+ + ) +} diff --git a/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx b/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx new file mode 100644 index 0000000000..d9e56af1b8 --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx @@ -0,0 +1,171 @@ +import Link from 'next/link' +import { useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { useRouter, useSearchParams } from 'next/navigation' +import { useContext } from 'use-context-selector' +import Button from '@/app/components/base/button' +import Toast from '@/app/components/base/toast' +import { emailRegex } from '@/config' +import { webAppLogin } from '@/service/common' +import Input from '@/app/components/base/input' +import I18NContext from '@/context/i18n' +import { noop } from 'lodash-es' +import { setAccessToken } from '@/app/components/share/utils' +import { fetchAccessToken } from '@/service/share' + +type MailAndPasswordAuthProps = { + isEmailSetup: boolean +} + +const passwordRegex = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/ + +export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAuthProps) { + const { t } = useTranslation() + const { locale } = useContext(I18NContext) + const router = useRouter() + const searchParams = useSearchParams() + const [showPassword, setShowPassword] = useState(false) + const emailFromLink = decodeURIComponent(searchParams.get('email') || '') + const [email, setEmail] = useState(emailFromLink) + const [password, setPassword] = useState('') + + const [isLoading, setIsLoading] = useState(false) + const redirectUrl = searchParams.get('redirect_url') + + const getAppCodeFromRedirectUrl = useCallback(() => { + const appCode = redirectUrl?.split('/').pop() + if (!appCode) + return null + + return appCode + }, [redirectUrl]) + const handleEmailPasswordLogin = async () => { + const appCode = getAppCodeFromRedirectUrl() + if (!email) { + Toast.notify({ type: 'error', message: t('login.error.emailEmpty') }) + return + } + if (!emailRegex.test(email)) { + Toast.notify({ + type: 'error', + message: t('login.error.emailInValid'), + }) + return + } + if (!password?.trim()) { + Toast.notify({ type: 'error', message: t('login.error.passwordEmpty') }) + return + } + if (!passwordRegex.test(password)) { + Toast.notify({ + type: 'error', + message: t('login.error.passwordInvalid'), + }) + return + } + if (!redirectUrl || !appCode) { + Toast.notify({ + type: 'error', + message: t('login.error.redirectUrlMissing'), + }) + return + } + try { + setIsLoading(true) + const loginData: Record = { + email, + password, + language: locale, + remember_me: true, + } + + const res = await webAppLogin({ + url: '/login', + body: loginData, + }) + if (res.result === 'success') { + localStorage.setItem('webapp_access_token', res.data.access_token) + const tokenResp = await fetchAccessToken({ appCode, webAppAccessToken: res.data.access_token }) + await setAccessToken(appCode, tokenResp.access_token) + router.replace(redirectUrl) + } + else { + Toast.notify({ + type: 'error', + message: res.data, + }) + } + } + + finally { + setIsLoading(false) + } + } + + return
+
+ +
+ setEmail(e.target.value)} + id="email" + type="email" + autoComplete="email" + placeholder={t('login.emailPlaceholder') || ''} + tabIndex={1} + /> +
+
+ +
+ +
+ setPassword(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') + handleEmailPasswordLogin() + }} + type={showPassword ? 'text' : 'password'} + autoComplete="current-password" + placeholder={t('login.passwordPlaceholder') || ''} + tabIndex={2} + /> +
+ +
+
+
+ +
+ +
+ +} diff --git a/web/app/(shareLayout)/webapp-signin/components/sso-auth.tsx b/web/app/(shareLayout)/webapp-signin/components/sso-auth.tsx new file mode 100644 index 0000000000..5d649322ba --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/components/sso-auth.tsx @@ -0,0 +1,88 @@ +'use client' +import { useRouter, useSearchParams } from 'next/navigation' +import type { FC } from 'react' +import { useCallback } from 'react' +import { useState } from 'react' +import { useTranslation } from 'react-i18next' +import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security' +import Toast from '@/app/components/base/toast' +import Button from '@/app/components/base/button' +import { SSOProtocol } from '@/types/feature' +import { fetchMembersOAuth2SSOUrl, fetchMembersOIDCSSOUrl, fetchMembersSAMLSSOUrl } from '@/service/share' + +type SSOAuthProps = { + protocol: SSOProtocol | '' +} + +const SSOAuth: FC = ({ + protocol, +}) => { + const router = useRouter() + const { t } = useTranslation() + const searchParams = useSearchParams() + + const redirectUrl = searchParams.get('redirect_url') + const getAppCodeFromRedirectUrl = useCallback(() => { + const appCode = redirectUrl?.split('/').pop() + if (!appCode) + return null + + return appCode + }, [redirectUrl]) + + const [isLoading, setIsLoading] = useState(false) + + const handleSSOLogin = () => { + const appCode = getAppCodeFromRedirectUrl() + if (!redirectUrl || !appCode) { + Toast.notify({ + type: 'error', + message: 'invalid redirect URL or app code', + }) + return + } + setIsLoading(true) + if (protocol === SSOProtocol.SAML) { + fetchMembersSAMLSSOUrl(appCode, redirectUrl).then((res) => { + router.push(res.url) + }).finally(() => { + setIsLoading(false) + }) + } + else if (protocol === SSOProtocol.OIDC) { + fetchMembersOIDCSSOUrl(appCode, redirectUrl).then((res) => { + router.push(res.url) + }).finally(() => { + setIsLoading(false) + }) + } + else if (protocol === SSOProtocol.OAuth2) { + fetchMembersOAuth2SSOUrl(appCode, redirectUrl).then((res) => { + router.push(res.url) + }).finally(() => { + setIsLoading(false) + }) + } + else { + Toast.notify({ + type: 'error', + message: 'invalid SSO protocol', + }) + setIsLoading(false) + } + } + + return ( + + ) +} + +export default SSOAuth diff --git a/web/app/(shareLayout)/webapp-signin/layout.tsx b/web/app/(shareLayout)/webapp-signin/layout.tsx new file mode 100644 index 0000000000..a03364d326 --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/layout.tsx @@ -0,0 +1,25 @@ +'use client' + +import cn from '@/utils/classnames' +import { useGlobalPublicStore } from '@/context/global-public-context' +import useDocumentTitle from '@/hooks/use-document-title' + +export default function SignInLayout({ children }: any) { + const { systemFeatures } = useGlobalPublicStore() + useDocumentTitle('') + return <> +
+
+ {/*
*/} +
+
+ {children} +
+
+ {systemFeatures.branding.enabled === false &&
+ © {new Date().getFullYear()} LangGenius, Inc. All rights reserved. +
} +
+
+ +} diff --git a/web/app/(shareLayout)/webapp-signin/normalForm.tsx b/web/app/(shareLayout)/webapp-signin/normalForm.tsx new file mode 100644 index 0000000000..d6bdf607ba --- /dev/null +++ b/web/app/(shareLayout)/webapp-signin/normalForm.tsx @@ -0,0 +1,176 @@ +import React, { useCallback, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import Link from 'next/link' +import { RiContractLine, RiDoorLockLine, RiErrorWarningFill } from '@remixicon/react' +import Loading from '@/app/components/base/loading' +import MailAndCodeAuth from './components/mail-and-code-auth' +import MailAndPasswordAuth from './components/mail-and-password-auth' +import SSOAuth from './components/sso-auth' +import cn from '@/utils/classnames' +import { LicenseStatus } from '@/types/feature' +import { IS_CE_EDITION } from '@/config' +import { useGlobalPublicStore } from '@/context/global-public-context' + +const NormalForm = () => { + const { t } = useTranslation() + + const [isLoading, setIsLoading] = useState(true) + const { systemFeatures } = useGlobalPublicStore() + const [authType, updateAuthType] = useState<'code' | 'password'>('password') + const [showORLine, setShowORLine] = useState(false) + const [allMethodsAreDisabled, setAllMethodsAreDisabled] = useState(false) + + const init = useCallback(async () => { + try { + setAllMethodsAreDisabled(!systemFeatures.enable_social_oauth_login && !systemFeatures.enable_email_code_login && !systemFeatures.enable_email_password_login && !systemFeatures.sso_enforced_for_signin) + setShowORLine((systemFeatures.enable_social_oauth_login || systemFeatures.sso_enforced_for_signin) && (systemFeatures.enable_email_code_login || systemFeatures.enable_email_password_login)) + updateAuthType(systemFeatures.enable_email_password_login ? 'password' : 'code') + } + catch (error) { + console.error(error) + setAllMethodsAreDisabled(true) + } + finally { setIsLoading(false) } + }, [systemFeatures]) + useEffect(() => { + init() + }, [init]) + if (isLoading) { + return
+ +
+ } + if (systemFeatures.license?.status === LicenseStatus.LOST) { + return
+
+
+
+ + +
+

{t('login.licenseLost')}

+

{t('login.licenseLostTip')}

+
+
+
+ } + if (systemFeatures.license?.status === LicenseStatus.EXPIRED) { + return
+
+
+
+ + +
+

{t('login.licenseExpired')}

+

{t('login.licenseExpiredTip')}

+
+
+
+ } + if (systemFeatures.license?.status === LicenseStatus.INACTIVE) { + return
+
+
+
+ + +
+

{t('login.licenseInactive')}

+

{t('login.licenseInactiveTip')}

+
+
+
+ } + + return ( + <> +
+
+

{t('login.pageTitle')}

+ {!systemFeatures.branding.enabled &&

{t('login.welcome')}

} +
+
+
+ {systemFeatures.sso_enforced_for_signin &&
+ +
} +
+ + {showORLine &&
+ +
+ {t('login.or')} +
+
} + { + (systemFeatures.enable_email_code_login || systemFeatures.enable_email_password_login) && <> + {systemFeatures.enable_email_code_login && authType === 'code' && <> + + {systemFeatures.enable_email_password_login &&
{ updateAuthType('password') }}> + {t('login.usePassword')} +
} + } + {systemFeatures.enable_email_password_login && authType === 'password' && <> + + {systemFeatures.enable_email_code_login &&
{ updateAuthType('code') }}> + {t('login.useVerificationCode')} +
} + } + + } + {allMethodsAreDisabled && <> +
+
+ +
+

{t('login.noLoginMethod')}

+

{t('login.noLoginMethodTip')}

+
+
+ +
+ } + {!systemFeatures.branding.enabled && <> +
+ {t('login.tosDesc')} +   + {t('login.tos')} +  &  + {t('login.pp')} +
+ {IS_CE_EDITION &&
+ {t('login.goToInit')} +   + {t('login.setAdminAccount')} +
} + } + +
+
+ + ) +} + +export default NormalForm diff --git a/web/app/(shareLayout)/webapp-signin/page.tsx b/web/app/(shareLayout)/webapp-signin/page.tsx index 668c3f312c..c12fde38dd 100644 --- a/web/app/(shareLayout)/webapp-signin/page.tsx +++ b/web/app/(shareLayout)/webapp-signin/page.tsx @@ -3,19 +3,20 @@ import { useRouter, useSearchParams } from 'next/navigation' import type { FC } from 'react' import React, { useCallback, useEffect } from 'react' import { useTranslation } from 'react-i18next' -import { RiDoorLockLine } from '@remixicon/react' -import cn from '@/utils/classnames' import Toast from '@/app/components/base/toast' -import { fetchWebOAuth2SSOUrl, fetchWebOIDCSSOUrl, fetchWebSAMLSSOUrl } from '@/service/share' -import { setAccessToken } from '@/app/components/share/utils' +import { removeAccessToken, setAccessToken } from '@/app/components/share/utils' import { useGlobalPublicStore } from '@/context/global-public-context' -import { SSOProtocol } from '@/types/feature' import Loading from '@/app/components/base/loading' import AppUnavailable from '@/app/components/base/app-unavailable' +import NormalForm from './normalForm' +import { AccessMode } from '@/models/access-control' +import ExternalMemberSsoAuth from './components/external-member-sso-auth' +import { fetchAccessToken } from '@/service/share' const WebSSOForm: FC = () => { const { t } = useTranslation() const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) + const webAppAccessMode = useGlobalPublicStore(s => s.webAppAccessMode) const searchParams = useSearchParams() const router = useRouter() @@ -23,10 +24,22 @@ const WebSSOForm: FC = () => { const tokenFromUrl = searchParams.get('web_sso_token') const message = searchParams.get('message') - const showErrorToast = (message: string) => { + const getSigninUrl = useCallback(() => { + const params = new URLSearchParams(searchParams) + params.delete('message') + return `/webapp-signin?${params.toString()}` + }, [searchParams]) + + const backToHome = useCallback(() => { + removeAccessToken() + const url = getSigninUrl() + router.replace(url) + }, [getSigninUrl, router]) + + const showErrorToast = (msg: string) => { Toast.notify({ type: 'error', - message, + message: msg, }) } @@ -38,102 +51,73 @@ const WebSSOForm: FC = () => { return appCode }, [redirectUrl]) - const processTokenAndRedirect = useCallback(async () => { - const appCode = getAppCodeFromRedirectUrl() - if (!appCode || !tokenFromUrl || !redirectUrl) { - showErrorToast('redirect url or app code or token is invalid.') - return - } - - await setAccessToken(appCode, tokenFromUrl) - router.push(redirectUrl) - }, [getAppCodeFromRedirectUrl, redirectUrl, router, tokenFromUrl]) - - const handleSSOLogin = useCallback(async () => { - const appCode = getAppCodeFromRedirectUrl() - if (!appCode || !redirectUrl) { - showErrorToast('redirect url or app code is invalid.') - return - } - - switch (systemFeatures.webapp_auth.sso_config.protocol) { - case SSOProtocol.SAML: { - const samlRes = await fetchWebSAMLSSOUrl(appCode, redirectUrl) - router.push(samlRes.url) - break - } - case SSOProtocol.OIDC: { - const oidcRes = await fetchWebOIDCSSOUrl(appCode, redirectUrl) - router.push(oidcRes.url) - break - } - case SSOProtocol.OAuth2: { - const oauth2Res = await fetchWebOAuth2SSOUrl(appCode, redirectUrl) - router.push(oauth2Res.url) - break - } - case '': - break - default: - showErrorToast('SSO protocol is not supported.') - } - }, [getAppCodeFromRedirectUrl, redirectUrl, router, systemFeatures.webapp_auth.sso_config.protocol]) - useEffect(() => { - const init = async () => { - if (message) { - showErrorToast(message) + (async () => { + if (message) return - } - if (!tokenFromUrl) { - await handleSSOLogin() + const appCode = getAppCodeFromRedirectUrl() + if (appCode && tokenFromUrl && redirectUrl) { + localStorage.setItem('webapp_access_token', tokenFromUrl) + const tokenResp = await fetchAccessToken({ appCode, webAppAccessToken: tokenFromUrl }) + await setAccessToken(appCode, tokenResp.access_token) + router.replace(redirectUrl) return } + if (appCode && redirectUrl && localStorage.getItem('webapp_access_token')) { + const tokenResp = await fetchAccessToken({ appCode, webAppAccessToken: localStorage.getItem('webapp_access_token') }) + await setAccessToken(appCode, tokenResp.access_token) + router.replace(redirectUrl) + } + })() + }, [getAppCodeFromRedirectUrl, redirectUrl, router, tokenFromUrl, message]) - await processTokenAndRedirect() - } + useEffect(() => { + if (webAppAccessMode && webAppAccessMode === AccessMode.PUBLIC && redirectUrl) + router.replace(redirectUrl) + }, [webAppAccessMode, router, redirectUrl]) - init() - }, [message, processTokenAndRedirect, tokenFromUrl, handleSSOLogin]) - if (tokenFromUrl) - return
- if (message) { + if (tokenFromUrl) { return
- +
} - if (systemFeatures.webapp_auth.enabled) { - if (systemFeatures.webapp_auth.allow_sso) { - return ( -
-
- -
-
- ) - } - return
-
-
- -
-

{t('login.webapp.noLoginMethod')}

-

{t('login.webapp.noLoginMethodTip')}

-
-
- -
+ if (message) { + return
+ + {t('share.login.backToHome')} +
+ } + if (!redirectUrl) { + showErrorToast('redirect url is invalid.') + return
+ +
+ } + if (webAppAccessMode && webAppAccessMode === AccessMode.PUBLIC) { + return
+
} - else { + if (!systemFeatures.webapp_auth.enabled) { return

{t('login.webapp.disabled')}

} + if (webAppAccessMode && (webAppAccessMode === AccessMode.ORGANIZATION || webAppAccessMode === AccessMode.SPECIFIC_GROUPS_MEMBERS)) { + return
+ +
+ } + + if (webAppAccessMode && webAppAccessMode === AccessMode.EXTERNAL_MEMBERS) + return + + return
+ + {t('share.login.backToHome')} +
} export default React.memo(WebSSOForm) diff --git a/web/app/components/app/app-access-control/index.tsx b/web/app/components/app/app-access-control/index.tsx index 2f15c8ec48..13faaea957 100644 --- a/web/app/components/app/app-access-control/index.tsx +++ b/web/app/components/app/app-access-control/index.tsx @@ -1,6 +1,6 @@ 'use client' -import { Dialog } from '@headlessui/react' -import { RiBuildingLine, RiGlobalLine } from '@remixicon/react' +import { Description as DialogDescription, DialogTitle } from '@headlessui/react' +import { RiBuildingLine, RiGlobalLine, RiVerifiedBadgeLine } from '@remixicon/react' import { useTranslation } from 'react-i18next' import { useCallback, useEffect } from 'react' import Button from '../../base/button' @@ -67,8 +67,8 @@ export default function AccessControl(props: AccessControlProps) { return
- {t('app.accessControlDialog.title')} - {t('app.accessControlDialog.description')} + {t('app.accessControlDialog.title')} + {t('app.accessControlDialog.description')}
@@ -80,12 +80,20 @@ export default function AccessControl(props: AccessControlProps) {

{t('app.accessControlDialog.accessItems.organization')}

- {!hideTip && }
+ +
+
+ +

{t('app.accessControlDialog.accessItems.external')}

+
+ {!hideTip && } +
+
diff --git a/web/app/components/app/app-access-control/specific-groups-or-members.tsx b/web/app/components/app/app-access-control/specific-groups-or-members.tsx index f4872f8c99..b30c8f1ba3 100644 --- a/web/app/components/app/app-access-control/specific-groups-or-members.tsx +++ b/web/app/components/app/app-access-control/specific-groups-or-members.tsx @@ -3,12 +3,10 @@ import { RiAlertFill, RiCloseCircleFill, RiLockLine, RiOrganizationChart } from import { useTranslation } from 'react-i18next' import { useCallback, useEffect } from 'react' import Avatar from '../../base/avatar' -import Divider from '../../base/divider' import Tooltip from '../../base/tooltip' import Loading from '../../base/loading' import useAccessControlStore from '../../../../context/access-control-store' import AddMemberOrGroupDialog from './add-member-or-group-pop' -import { useGlobalPublicStore } from '@/context/global-public-context' import type { AccessControlAccount, AccessControlGroup } from '@/models/access-control' import { AccessMode } from '@/models/access-control' import { useAppWhiteListSubjects } from '@/service/access-control' @@ -19,11 +17,6 @@ export default function SpecificGroupsOrMembers() { const setSpecificGroups = useAccessControlStore(s => s.setSpecificGroups) const setSpecificMembers = useAccessControlStore(s => s.setSpecificMembers) const { t } = useTranslation() - const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) - const hideTip = systemFeatures.webapp_auth.enabled - && (systemFeatures.webapp_auth.allow_sso - || systemFeatures.webapp_auth.allow_email_password_login - || systemFeatures.webapp_auth.allow_email_code_login) const { isPending, data } = useAppWhiteListSubjects(appId, Boolean(appId) && currentMenu === AccessMode.SPECIFIC_GROUPS_MEMBERS) useEffect(() => { @@ -37,7 +30,6 @@ export default function SpecificGroupsOrMembers() {

{t('app.accessControlDialog.accessItems.specific')}

- {!hideTip && }
} @@ -48,10 +40,6 @@ export default function SpecificGroupsOrMembers() {

{t('app.accessControlDialog.accessItems.specific')}

- {!hideTip && <> - - - }
diff --git a/web/app/components/app/app-publisher/index.tsx b/web/app/components/app/app-publisher/index.tsx index 8d0028c7d7..5825bb72ee 100644 --- a/web/app/components/app/app-publisher/index.tsx +++ b/web/app/components/app/app-publisher/index.tsx @@ -9,11 +9,14 @@ import dayjs from 'dayjs' import { RiArrowDownSLine, RiArrowRightSLine, + RiBuildingLine, + RiGlobalLine, RiLockLine, RiPlanetLine, RiPlayCircleLine, RiPlayList2Line, RiTerminalBoxLine, + RiVerifiedBadgeLine, } from '@remixicon/react' import { useKeyPress } from 'ahooks' import { getKeyboardKeyCodeBySystem } from '../../workflow/utils' @@ -276,10 +279,30 @@ const AppPublisher = ({ setShowAppAccessControl(true) }}>
- - {appDetail?.access_mode === AccessMode.ORGANIZATION &&

{t('app.accessControlDialog.accessItems.organization')}

} - {appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS &&

{t('app.accessControlDialog.accessItems.specific')}

} - {appDetail?.access_mode === AccessMode.PUBLIC &&

{t('app.accessControlDialog.accessItems.anyone')}

} + {appDetail?.access_mode === AccessMode.ORGANIZATION + && <> + +

{t('app.accessControlDialog.accessItems.organization')}

+ + } + {appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS + && <> + +

{t('app.accessControlDialog.accessItems.specific')}

+ + } + {appDetail?.access_mode === AccessMode.PUBLIC + && <> + +

{t('app.accessControlDialog.accessItems.anyone')}

+ + } + {appDetail?.access_mode === AccessMode.EXTERNAL_MEMBERS + && <> + +

{t('app.accessControlDialog.accessItems.external')}

+ + }
{!isAppAccessSet &&

{t('app.publishApp.notSet')}

}
diff --git a/web/app/components/app/overview/appCard.tsx b/web/app/components/app/overview/appCard.tsx index 9b283cdf5e..9f3b3ac4a6 100644 --- a/web/app/components/app/overview/appCard.tsx +++ b/web/app/components/app/overview/appCard.tsx @@ -5,10 +5,13 @@ import { useTranslation } from 'react-i18next' import { RiArrowRightSLine, RiBookOpenLine, + RiBuildingLine, RiEqualizer2Line, RiExternalLinkLine, + RiGlobalLine, RiLockLine, RiPaintBrushLine, + RiVerifiedBadgeLine, RiWindowLine, } from '@remixicon/react' import SettingsModal from './settings' @@ -248,11 +251,30 @@ function AppCard({
- - {appDetail?.access_mode === AccessMode.ORGANIZATION &&

{t('app.accessControlDialog.accessItems.organization')}

} - {appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS &&

{t('app.accessControlDialog.accessItems.specific')}

} - {appDetail?.access_mode === AccessMode.PUBLIC &&

{t('app.accessControlDialog.accessItems.anyone')}

} -
+ {appDetail?.access_mode === AccessMode.ORGANIZATION + && <> + +

{t('app.accessControlDialog.accessItems.organization')}

+ + } + {appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS + && <> + +

{t('app.accessControlDialog.accessItems.specific')}

+ + } + {appDetail?.access_mode === AccessMode.PUBLIC + && <> + +

{t('app.accessControlDialog.accessItems.anyone')}

+ + } + {appDetail?.access_mode === AccessMode.EXTERNAL_MEMBERS + && <> + +

{t('app.accessControlDialog.accessItems.external')}

+ + }
{!isAppAccessSet &&

{t('app.publishApp.notSet')}

}
diff --git a/web/app/components/base/app-unavailable.tsx b/web/app/components/base/app-unavailable.tsx index 4e835cbfcf..928c850262 100644 --- a/web/app/components/base/app-unavailable.tsx +++ b/web/app/components/base/app-unavailable.tsx @@ -1,4 +1,5 @@ 'use client' +import classNames from '@/utils/classnames' import type { FC } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' @@ -7,17 +8,19 @@ type IAppUnavailableProps = { code?: number | string isUnknownReason?: boolean unknownReason?: string + className?: string } const AppUnavailable: FC = ({ code = 404, isUnknownReason, unknownReason, + className, }) => { const { t } = useTranslation() return ( -
+

({ - accessMode: AccessMode.SPECIFIC_GROUPS_MEMBERS, userCanAccess: false, currentConversationId: '', appPrevChatTree: [], diff --git a/web/app/components/base/chat/chat-with-history/hooks.tsx b/web/app/components/base/chat/chat-with-history/hooks.tsx index dd7cb14b25..32f74e6457 100644 --- a/web/app/components/base/chat/chat-with-history/hooks.tsx +++ b/web/app/components/base/chat/chat-with-history/hooks.tsx @@ -43,9 +43,8 @@ import { useAppFavicon } from '@/hooks/use-app-favicon' import { InputVarType } from '@/app/components/workflow/types' import { TransferMethod } from '@/types/app' import { noop } from 'lodash-es' -import { useGetAppAccessMode, useGetUserCanAccessApp } from '@/service/access-control' +import { useGetUserCanAccessApp } from '@/service/access-control' import { useGlobalPublicStore } from '@/context/global-public-context' -import { AccessMode } from '@/models/access-control' function getFormattedChatList(messages: any[]) { const newChatList: ChatItem[] = [] @@ -77,11 +76,6 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => { const isInstalledApp = useMemo(() => !!installedAppInfo, [installedAppInfo]) const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR(installedAppInfo ? null : 'appInfo', fetchAppInfo) - const { isPending: isGettingAccessMode, data: appAccessMode } = useGetAppAccessMode({ - appId: installedAppInfo?.app.id || appInfo?.app_id, - isInstalledApp, - enabled: systemFeatures.webapp_auth.enabled, - }) const { isPending: isCheckingPermission, data: userCanAccessResult } = useGetUserCanAccessApp({ appId: installedAppInfo?.app.id || appInfo?.app_id, isInstalledApp, @@ -492,8 +486,7 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => { return { appInfoError, - appInfoLoading: appInfoLoading || (systemFeatures.webapp_auth.enabled && (isGettingAccessMode || isCheckingPermission)), - accessMode: systemFeatures.webapp_auth.enabled ? appAccessMode?.accessMode : AccessMode.PUBLIC, + appInfoLoading: appInfoLoading || (systemFeatures.webapp_auth.enabled && isCheckingPermission), userCanAccess: systemFeatures.webapp_auth.enabled ? userCanAccessResult?.result : true, isInstalledApp, appId, diff --git a/web/app/components/base/chat/chat-with-history/index.tsx b/web/app/components/base/chat/chat-with-history/index.tsx index de023e7f58..1fd1383196 100644 --- a/web/app/components/base/chat/chat-with-history/index.tsx +++ b/web/app/components/base/chat/chat-with-history/index.tsx @@ -124,7 +124,6 @@ const ChatWithHistoryWrap: FC = ({ const { appInfoError, appInfoLoading, - accessMode, userCanAccess, appData, appParams, @@ -169,7 +168,6 @@ const ChatWithHistoryWrap: FC = ({ appInfoError, appInfoLoading, appData, - accessMode, userCanAccess, appParams, appMeta, diff --git a/web/app/components/base/chat/chat-with-history/sidebar/index.tsx b/web/app/components/base/chat/chat-with-history/sidebar/index.tsx index fd317ccf91..4e50c1cb79 100644 --- a/web/app/components/base/chat/chat-with-history/sidebar/index.tsx +++ b/web/app/components/base/chat/chat-with-history/sidebar/index.tsx @@ -19,7 +19,6 @@ import RenameModal from '@/app/components/base/chat/chat-with-history/sidebar/re import DifyLogo from '@/app/components/base/logo/dify-logo' import type { ConversationItem } from '@/models/share' import cn from '@/utils/classnames' -import { AccessMode } from '@/models/access-control' import { useGlobalPublicStore } from '@/context/global-public-context' type Props = { @@ -30,7 +29,6 @@ const Sidebar = ({ isPanel }: Props) => { const { t } = useTranslation() const { isInstalledApp, - accessMode, appData, handleNewConversation, pinnedConversationList, @@ -140,7 +138,7 @@ const Sidebar = ({ isPanel }: Props) => { )}

- + {/* powered by */}
{!appData?.custom_config?.remove_webapp_brand && ( diff --git a/web/app/components/base/chat/embedded-chatbot/context.tsx b/web/app/components/base/chat/embedded-chatbot/context.tsx index 5964efd806..d24265ed9e 100644 --- a/web/app/components/base/chat/embedded-chatbot/context.tsx +++ b/web/app/components/base/chat/embedded-chatbot/context.tsx @@ -15,10 +15,8 @@ import type { ConversationItem, } from '@/models/share' import { noop } from 'lodash-es' -import { AccessMode } from '@/models/access-control' export type EmbeddedChatbotContextValue = { - accessMode?: AccessMode userCanAccess?: boolean appInfoError?: any appInfoLoading?: boolean @@ -58,7 +56,6 @@ export type EmbeddedChatbotContextValue = { export const EmbeddedChatbotContext = createContext({ userCanAccess: false, - accessMode: AccessMode.SPECIFIC_GROUPS_MEMBERS, currentConversationId: '', appPrevChatList: [], pinnedConversationList: [], diff --git a/web/app/components/base/chat/embedded-chatbot/hooks.tsx b/web/app/components/base/chat/embedded-chatbot/hooks.tsx index 40c56eca7b..0158e8d041 100644 --- a/web/app/components/base/chat/embedded-chatbot/hooks.tsx +++ b/web/app/components/base/chat/embedded-chatbot/hooks.tsx @@ -36,9 +36,8 @@ import { InputVarType } from '@/app/components/workflow/types' import { TransferMethod } from '@/types/app' import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils' import { noop } from 'lodash-es' -import { useGetAppAccessMode, useGetUserCanAccessApp } from '@/service/access-control' +import { useGetUserCanAccessApp } from '@/service/access-control' import { useGlobalPublicStore } from '@/context/global-public-context' -import { AccessMode } from '@/models/access-control' function getFormattedChatList(messages: any[]) { const newChatList: ChatItem[] = [] @@ -70,11 +69,6 @@ export const useEmbeddedChatbot = () => { const isInstalledApp = false const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR('appInfo', fetchAppInfo) - const { isPending: isGettingAccessMode, data: appAccessMode } = useGetAppAccessMode({ - appId: appInfo?.app_id, - isInstalledApp, - enabled: systemFeatures.webapp_auth.enabled, - }) const { isPending: isCheckingPermission, data: userCanAccessResult } = useGetUserCanAccessApp({ appId: appInfo?.app_id, isInstalledApp, @@ -385,8 +379,7 @@ export const useEmbeddedChatbot = () => { return { appInfoError, - appInfoLoading: appInfoLoading || (systemFeatures.webapp_auth.enabled && (isGettingAccessMode || isCheckingPermission)), - accessMode: systemFeatures.webapp_auth.enabled ? appAccessMode?.accessMode : AccessMode.PUBLIC, + appInfoLoading: appInfoLoading || (systemFeatures.webapp_auth.enabled && isCheckingPermission), userCanAccess: systemFeatures.webapp_auth.enabled ? userCanAccessResult?.result : true, isInstalledApp, allowResetChat, diff --git a/web/app/components/share/text-generation/menu-dropdown.tsx b/web/app/components/share/text-generation/menu-dropdown.tsx index 19b660b083..adb926c7ca 100644 --- a/web/app/components/share/text-generation/menu-dropdown.tsx +++ b/web/app/components/share/text-generation/menu-dropdown.tsx @@ -6,9 +6,8 @@ import type { Placement } from '@floating-ui/react' import { RiEqualizer2Line, } from '@remixicon/react' -import { useRouter } from 'next/navigation' +import { usePathname, useRouter } from 'next/navigation' import Divider from '../../base/divider' -import { removeAccessToken } from '../utils' import InfoModal from './info-modal' import ActionButton from '@/app/components/base/action-button' import { @@ -19,6 +18,8 @@ import { import ThemeSwitcher from '@/app/components/base/theme-switcher' import type { SiteInfo } from '@/models/share' import cn from '@/utils/classnames' +import { useGlobalPublicStore } from '@/context/global-public-context' +import { AccessMode } from '@/models/access-control' type Props = { data?: SiteInfo @@ -31,7 +32,9 @@ const MenuDropdown: FC = ({ placement, hideLogout, }) => { + const webAppAccessMode = useGlobalPublicStore(s => s.webAppAccessMode) const router = useRouter() + const pathname = usePathname() const { t } = useTranslation() const [open, doSetOpen] = useState(false) const openRef = useRef(open) @@ -45,9 +48,10 @@ const MenuDropdown: FC = ({ }, [setOpen]) const handleLogout = useCallback(() => { - removeAccessToken() - router.replace(`/webapp-signin?redirect_url=${window.location.href}`) - }, [router]) + localStorage.removeItem('token') + localStorage.removeItem('webapp_access_token') + router.replace(`/webapp-signin?redirect_url=${pathname}`) + }, [router, pathname]) const [show, setShow] = useState(false) @@ -92,6 +96,16 @@ const MenuDropdown: FC = ({ className='system-md-regular cursor-pointer rounded-lg px-3 py-1.5 text-text-secondary hover:bg-state-base-hover' >{t('common.userProfile.about')}
+ {!(hideLogout || webAppAccessMode === AccessMode.EXTERNAL_MEMBERS || webAppAccessMode === AccessMode.PUBLIC) && ( +
+
+ {t('common.userProfile.logout')} +
+
+ )}
diff --git a/web/app/components/share/utils.ts b/web/app/components/share/utils.ts index 9ce891a50c..d793d48b48 100644 --- a/web/app/components/share/utils.ts +++ b/web/app/components/share/utils.ts @@ -10,8 +10,8 @@ export const getInitialTokenV2 = (): Record => ({ version: 2, }) -export const checkOrSetAccessToken = async () => { - const sharedToken = globalThis.location.pathname.split('/').slice(-1)[0] +export const checkOrSetAccessToken = async (appCode?: string) => { + const sharedToken = appCode || globalThis.location.pathname.split('/').slice(-1)[0] const userId = (await getProcessedSystemVariablesFromUrlParams()).user_id const accessToken = localStorage.getItem('token') || JSON.stringify(getInitialTokenV2()) let accessTokenJson = getInitialTokenV2() @@ -23,8 +23,10 @@ export const checkOrSetAccessToken = async () => { catch { } + if (!accessTokenJson[sharedToken]?.[userId || 'DEFAULT']) { - const res = await fetchAccessToken(sharedToken, userId) + const webAppAccessToken = localStorage.getItem('webapp_access_token') + const res = await fetchAccessToken({ appCode: sharedToken, userId, webAppAccessToken }) accessTokenJson[sharedToken] = { ...accessTokenJson[sharedToken], [userId || 'DEFAULT']: res.access_token, @@ -33,7 +35,7 @@ export const checkOrSetAccessToken = async () => { } } -export const setAccessToken = async (sharedToken: string, token: string, user_id?: string) => { +export const setAccessToken = (sharedToken: string, token: string, user_id?: string) => { const accessToken = localStorage.getItem('token') || JSON.stringify(getInitialTokenV2()) let accessTokenJson = getInitialTokenV2() try { @@ -69,6 +71,7 @@ export const removeAccessToken = () => { } localStorage.removeItem(CONVERSATION_ID_INFO) + localStorage.removeItem('webapp_access_token') delete accessTokenJson[sharedToken] localStorage.setItem('token', JSON.stringify(accessTokenJson)) diff --git a/web/app/signin/LoginLogo.tsx b/web/app/signin/LoginLogo.tsx index 0753d1f98a..73dfb88205 100644 --- a/web/app/signin/LoginLogo.tsx +++ b/web/app/signin/LoginLogo.tsx @@ -1,8 +1,8 @@ 'use client' import type { FC } from 'react' import classNames from '@/utils/classnames' -import { useSelector } from '@/context/app-context' import { useGlobalPublicStore } from '@/context/global-public-context' +import { useTheme } from 'next-themes' type LoginLogoProps = { className?: string @@ -12,11 +12,7 @@ const LoginLogo: FC = ({ className, }) => { const { systemFeatures } = useGlobalPublicStore() - const { theme } = useSelector((s) => { - return { - theme: s.theme, - } - }) + const { theme } = useTheme() let src = theme === 'light' ? '/logo/logo-site.png' : `/logo/logo-site-${theme}.png` if (systemFeatures.branding.enabled) diff --git a/web/context/global-public-context.tsx b/web/context/global-public-context.tsx index 5aa5e7a302..26ad84be65 100644 --- a/web/context/global-public-context.tsx +++ b/web/context/global-public-context.tsx @@ -7,19 +7,24 @@ import type { SystemFeatures } from '@/types/feature' import { defaultSystemFeatures } from '@/types/feature' import { getSystemFeatures } from '@/service/common' import Loading from '@/app/components/base/loading' +import { AccessMode } from '@/models/access-control' type GlobalPublicStore = { - isPending: boolean - setIsPending: (isPending: boolean) => void + isGlobalPending: boolean + setIsGlobalPending: (isPending: boolean) => void systemFeatures: SystemFeatures setSystemFeatures: (systemFeatures: SystemFeatures) => void + webAppAccessMode: AccessMode, + setWebAppAccessMode: (webAppAccessMode: AccessMode) => void } export const useGlobalPublicStore = create(set => ({ - isPending: true, - setIsPending: (isPending: boolean) => set(() => ({ isPending })), + isGlobalPending: true, + setIsGlobalPending: (isPending: boolean) => set(() => ({ isGlobalPending: isPending })), systemFeatures: defaultSystemFeatures, setSystemFeatures: (systemFeatures: SystemFeatures) => set(() => ({ systemFeatures })), + webAppAccessMode: AccessMode.PUBLIC, + setWebAppAccessMode: (webAppAccessMode: AccessMode) => set(() => ({ webAppAccessMode })), })) const GlobalPublicStoreProvider: FC = ({ @@ -29,7 +34,7 @@ const GlobalPublicStoreProvider: FC = ({ queryKey: ['systemFeatures'], queryFn: getSystemFeatures, }) - const { setSystemFeatures, setIsPending } = useGlobalPublicStore() + const { setSystemFeatures, setIsGlobalPending: setIsPending } = useGlobalPublicStore() useEffect(() => { if (data) setSystemFeatures({ ...defaultSystemFeatures, ...data }) diff --git a/web/hooks/use-document-title.spec.ts b/web/hooks/use-document-title.spec.ts index 88239ffbdf..a8d3d56cff 100644 --- a/web/hooks/use-document-title.spec.ts +++ b/web/hooks/use-document-title.spec.ts @@ -11,7 +11,7 @@ describe('title should be empty if systemFeatures is pending', () => { act(() => { useGlobalPublicStore.setState({ systemFeatures: { ...defaultSystemFeatures, branding: { ...defaultSystemFeatures.branding, enabled: false } }, - isPending: true, + isGlobalPending: true, }) }) it('document title should be empty if set title', () => { @@ -28,7 +28,7 @@ describe('use default branding', () => { beforeEach(() => { act(() => { useGlobalPublicStore.setState({ - isPending: false, + isGlobalPending: false, systemFeatures: { ...defaultSystemFeatures, branding: { ...defaultSystemFeatures.branding, enabled: false } }, }) }) @@ -48,7 +48,7 @@ describe('use specific branding', () => { beforeEach(() => { act(() => { useGlobalPublicStore.setState({ - isPending: false, + isGlobalPending: false, systemFeatures: { ...defaultSystemFeatures, branding: { ...defaultSystemFeatures.branding, enabled: true, application_title: 'Test' } }, }) }) diff --git a/web/hooks/use-document-title.ts b/web/hooks/use-document-title.ts index 10275a196f..2c848a1f56 100644 --- a/web/hooks/use-document-title.ts +++ b/web/hooks/use-document-title.ts @@ -3,7 +3,7 @@ import { useGlobalPublicStore } from '@/context/global-public-context' import { useFavicon, useTitle } from 'ahooks' export default function useDocumentTitle(title: string) { - const isPending = useGlobalPublicStore(s => s.isPending) + const isPending = useGlobalPublicStore(s => s.isGlobalPending) const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) const prefix = title ? `${title} - ` : '' let titleStr = '' diff --git a/web/i18n/en-US/app.ts b/web/i18n/en-US/app.ts index 20a80ba4cd..ccfe23ead6 100644 --- a/web/i18n/en-US/app.ts +++ b/web/i18n/en-US/app.ts @@ -197,9 +197,10 @@ const translation = { }, accessControl: 'Web App Access Control', accessItemsDescription: { - anyone: 'Anyone can access the web app', - specific: 'Only specific groups or members can access the web app', - organization: 'Anyone in the organization can access the web app', + anyone: 'Anyone can access the web app (no login required)', + specific: 'Only specific members within the platform can access the Web application', + organization: 'All members within the platform can access the Web application', + external: 'Only authenticated external users can access the Web application', }, accessControlDialog: { title: 'Web App Access Control', @@ -207,15 +208,16 @@ const translation = { accessLabel: 'Who has access', accessItems: { anyone: 'Anyone with the link', - specific: 'Specific groups or members', - organization: 'Only members within the enterprise', + specific: 'Specific members within the platform', + organization: 'All members within the platform', + external: 'Authenticated external users', }, groups_one: '{{count}} GROUP', groups_other: '{{count}} GROUPS', members_one: '{{count}} MEMBER', members_other: '{{count}} MEMBERS', noGroupsOrMembers: 'No groups or members selected', - webAppSSONotEnabledTip: 'Please contact enterprise administrator to configure the web app authentication method.', + webAppSSONotEnabledTip: 'Please contact your organization administrator to configure external authentication for the Web application.', operateGroupAndMember: { searchPlaceholder: 'Search groups and members', allMembers: 'All members', diff --git a/web/i18n/en-US/share-app.ts b/web/i18n/en-US/share-app.ts index bf99005d71..ab589ffb76 100644 --- a/web/i18n/en-US/share-app.ts +++ b/web/i18n/en-US/share-app.ts @@ -77,6 +77,9 @@ const translation = { atLeastOne: 'Please input at least one row in the uploaded file.', }, }, + login: { + backToHome: 'Back to Home', + }, } export default translation diff --git a/web/i18n/ja-JP/app.ts b/web/i18n/ja-JP/app.ts index b4fc8d4d82..b501bc129e 100644 --- a/web/i18n/ja-JP/app.ts +++ b/web/i18n/ja-JP/app.ts @@ -210,30 +210,27 @@ const translation = { }, accessControl: 'Web アプリアクセス制御', accessItemsDescription: { - anyone: '誰でも Web アプリにアクセス可能', - specific: '特定のグループまたはメンバーのみが Web アプリにアクセス可能', - organization: '組織内の誰でも Web アプリにアクセス可能', + anyone: '誰でもこの web アプリにアクセスできます(ログイン不要)', + specific: '特定のプラットフォーム内メンバーのみがこの Web アプリにアクセスできます', + organization: 'プラットフォーム内の全メンバーがこの Web アプリにアクセスできます', + external: '認証済みの外部ユーザーのみがこの Web アプリにアクセスできます', }, accessControlDialog: { title: 'アクセス権限', description: 'Web アプリのアクセス権限を設定します', accessLabel: '誰がアクセスできますか', - accessItemsDescription: { - anyone: '誰でも Web アプリにアクセス可能です', - specific: '特定のグループやメンバーが Web アプリにアクセス可能です', - organization: '組織内の誰でも Web アプリにアクセス可能です', - }, accessItems: { - anyone: 'すべてのユーザー', - specific: '特定のグループメンバー', - organization: 'グループ内の全員', + anyone: 'リンクを知っているすべてのユーザー', + specific: '特定のプラットフォーム内メンバー', + organization: 'プラットフォーム内の全メンバー', + external: '認証済みの外部ユーザー', }, groups_one: '{{count}} グループ', groups_other: '{{count}} グループ', members_one: '{{count}} メンバー', members_other: '{{count}} メンバー', noGroupsOrMembers: 'グループまたはメンバーが選択されていません', - webAppSSONotEnabledTip: 'Web アプリの認証方式設定については、企業管理者へご連絡ください。', + webAppSSONotEnabledTip: 'Web アプリの外部認証方式を設定するには、組織の管理者にお問い合わせください。', operateGroupAndMember: { searchPlaceholder: 'グループやメンバーを検索', allMembers: 'すべてのメンバー', diff --git a/web/i18n/ja-JP/share-app.ts b/web/i18n/ja-JP/share-app.ts index 9e76f6518a..20dad7faec 100644 --- a/web/i18n/ja-JP/share-app.ts +++ b/web/i18n/ja-JP/share-app.ts @@ -73,6 +73,9 @@ const translation = { atLeastOne: '1 行以上のデータが必要です', }, }, + login: { + backToHome: 'ホームに戻る', + }, } export default translation diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index bdd7d98d9b..4ec1e65059 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -198,30 +198,27 @@ const translation = { }, accessControl: 'Web 应用访问控制', accessItemsDescription: { - anyone: '任何人可以访问 web 应用', - specific: '特定组或成员可以访问 web 应用', - organization: '组织内任何人可以访问 web 应用', + anyone: '任何人都可以访问该 web 应用(无需登录)', + specific: '仅指定的平台内成员可访问该 Web 应用', + organization: '平台内所有成员均可访问该 Web 应用', + external: '仅经认证的外部用户可访问该 Web 应用', }, accessControlDialog: { title: 'Web 应用访问权限', description: '设置 web 应用访问权限。', accessLabel: '谁可以访问', - accessItemsDescription: { - anyone: '任何人可以访问 web 应用', - specific: '特定组或成员可以访问 web 应用', - organization: '组织内任何人可以访问 web 应用', - }, accessItems: { anyone: '任何人', - specific: '特定组或成员', - organization: '组织内任何人', + specific: '平台内指定成员', + organization: '平台内所有成员', + external: '经认证的外部用户', }, groups_one: '{{count}} 个组', groups_other: '{{count}} 个组', members_one: '{{count}} 个成员', members_other: '{{count}} 个成员', noGroupsOrMembers: '未选择分组或成员', - webAppSSONotEnabledTip: '请联系企业管理员配置 web 应用的身份认证方式。', + webAppSSONotEnabledTip: '请联系企业管理员配置 Web 应用外部认证方式。', operateGroupAndMember: { searchPlaceholder: '搜索组或成员', allMembers: '所有成员', diff --git a/web/i18n/zh-Hans/share-app.ts b/web/i18n/zh-Hans/share-app.ts index 4ea2ad6f49..ce1270dae8 100644 --- a/web/i18n/zh-Hans/share-app.ts +++ b/web/i18n/zh-Hans/share-app.ts @@ -73,6 +73,9 @@ const translation = { atLeastOne: '上传文件的内容不能少于一条', }, }, + login: { + backToHome: '返回首页', + }, } export default translation diff --git a/web/models/access-control.ts b/web/models/access-control.ts index 8ad9cc6491..911662b5c4 100644 --- a/web/models/access-control.ts +++ b/web/models/access-control.ts @@ -7,6 +7,7 @@ export enum AccessMode { PUBLIC = 'public', SPECIFIC_GROUPS_MEMBERS = 'private', ORGANIZATION = 'private_all', + EXTERNAL_MEMBERS = 'sso_verified', } export type AccessControlGroup = { diff --git a/web/service/base.ts b/web/service/base.ts index 4b08736288..c3cafe600b 100644 --- a/web/service/base.ts +++ b/web/service/base.ts @@ -109,6 +109,7 @@ function unicodeToChar(text: string) { } function requiredWebSSOLogin(message?: string) { + removeAccessToken() const params = new URLSearchParams() params.append('redirect_url', globalThis.location.pathname) if (message) diff --git a/web/service/common.ts b/web/service/common.ts index e76cfb4196..700cd4bf51 100644 --- a/web/service/common.ts +++ b/web/service/common.ts @@ -52,6 +52,9 @@ type LoginResponse = LoginSuccess | LoginFail export const login: Fetcher }> = ({ url, body }) => { return post(url, { body }) as Promise } +export const webAppLogin: Fetcher }> = ({ url, body }) => { + return post(url, { body }, { isPublicAPI: true }) as Promise +} export const fetchNewToken: Fetcher }> = ({ body }) => { return post('/refresh-token', { body }) as Promise @@ -324,6 +327,16 @@ export const verifyForgotPasswordToken: Fetcher = ({ url, body }) => post(url, { body }) +export const sendWebAppForgotPasswordEmail: Fetcher = ({ url, body }) => + post(url, { body }, { isPublicAPI: true }) + +export const verifyWebAppForgotPasswordToken: Fetcher = ({ url, body }) => { + return post(url, { body }, { isPublicAPI: true }) as Promise +} + +export const changeWebAppPasswordWithToken: Fetcher = ({ url, body }) => + post(url, { body }, { isPublicAPI: true }) + export const uploadRemoteFileInfo = (url: string, isPublic?: boolean) => { return post<{ id: string; name: string; size: number; mime_type: string; url: string }>('/remote-files/upload', { body: { url } }, { isPublicAPI: isPublic }) } @@ -340,6 +353,18 @@ export const sendResetPasswordCode = (email: string, language = 'en-US') => export const verifyResetPasswordCode = (body: { email: string; code: string; token: string }) => post('/forgot-password/validity', { body }) +export const sendWebAppEMailLoginCode = (email: string, language = 'en-US') => + post('/email-code-login', { body: { email, language } }, { isPublicAPI: true }) + +export const webAppEmailLoginWithCode = (data: { email: string; code: string; token: string }) => + post('/email-code-login/validity', { body: data }, { isPublicAPI: true }) + +export const sendWebAppResetPasswordCode = (email: string, language = 'en-US') => + post('/forgot-password', { body: { email, language } }, { isPublicAPI: true }) + +export const verifyWebAppResetPasswordCode = (body: { email: string; code: string; token: string }) => + post('/forgot-password/validity', { body }, { isPublicAPI: true }) + export const sendDeleteAccountCode = () => get('/account/delete/verify') diff --git a/web/service/share.ts b/web/service/share.ts index 7fb1562185..6a2a7e5b16 100644 --- a/web/service/share.ts +++ b/web/service/share.ts @@ -214,6 +214,34 @@ export const fetchWebOAuth2SSOUrl = async (appCode: string, redirectUrl: string) }) as Promise<{ url: string }> } +export const fetchMembersSAMLSSOUrl = async (appCode: string, redirectUrl: string) => { + return (getAction('get', false))(getUrl('/enterprise/sso/members/saml/login', false, ''), { + params: { + app_code: appCode, + redirect_url: redirectUrl, + }, + }) as Promise<{ url: string }> +} + +export const fetchMembersOIDCSSOUrl = async (appCode: string, redirectUrl: string) => { + return (getAction('get', false))(getUrl('/enterprise/sso/members/oidc/login', false, ''), { + params: { + app_code: appCode, + redirect_url: redirectUrl, + }, + + }) as Promise<{ url: string }> +} + +export const fetchMembersOAuth2SSOUrl = async (appCode: string, redirectUrl: string) => { + return (getAction('get', false))(getUrl('/enterprise/sso/members/oauth2/login', false, ''), { + params: { + app_code: appCode, + redirect_url: redirectUrl, + }, + }) as Promise<{ url: string }> +} + export const fetchAppMeta = async (isInstalledApp: boolean, installedAppId = '') => { return (getAction('get', isInstalledApp))(getUrl('meta', isInstalledApp, installedAppId)) as Promise } @@ -258,10 +286,13 @@ export const textToAudioStream = (url: string, isPublicAPI: boolean, header: { c return (getAction('post', !isPublicAPI))(url, { body, header }, { needAllResponseContent: true }) } -export const fetchAccessToken = async (appCode: string, userId?: string) => { +export const fetchAccessToken = async ({ appCode, userId, webAppAccessToken }: { appCode: string, userId?: string, webAppAccessToken?: string | null }) => { const headers = new Headers() headers.append('X-App-Code', appCode) - const url = userId ? `/passport?user_id=${encodeURIComponent(userId)}` : '/passport' + const params = new URLSearchParams() + webAppAccessToken && params.append('web_app_access_token', webAppAccessToken) + userId && params.append('user_id', userId) + const url = `/passport?${params.toString()}` return get(url, { headers }) as Promise<{ access_token: string }> } @@ -278,3 +309,7 @@ export const getUserCanAccess = (appId: string, isInstalledApp: boolean) => { return get<{ result: boolean }>(`/webapp/permission?appId=${appId}`) } + +export const getAppAccessModeByAppCode = (appCode: string) => { + return get<{ accessMode: AccessMode }>(`/webapp/access-mode?appCode=${appCode}`) +} diff --git a/web/service/use-share.ts b/web/service/use-share.ts new file mode 100644 index 0000000000..b8f96f6cc5 --- /dev/null +++ b/web/service/use-share.ts @@ -0,0 +1,17 @@ +import { useQuery } from '@tanstack/react-query' +import { getAppAccessModeByAppCode } from './share' + +const NAME_SPACE = 'webapp' + +export const useAppAccessModeByCode = (code: string | null) => { + return useQuery({ + queryKey: [NAME_SPACE, 'appAccessMode', code], + queryFn: () => { + if (!code) + return null + + return getAppAccessModeByAppCode(code) + }, + enabled: !!code, + }) +} From 1fbbbb735db1237aa36dcc0d976fda617ab5c71b Mon Sep 17 00:00:00 2001 From: XiaoBa <94062266+XiaoBa-Yu@users.noreply.github.com> Date: Thu, 5 Jun 2025 11:07:54 +0800 Subject: [PATCH 65/73] fix: the locale format(#20662) (#20665) Co-authored-by: Xiaoba Yu --- web/app/components/header/maintenance-notice.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/app/components/header/maintenance-notice.tsx b/web/app/components/header/maintenance-notice.tsx index 78715bb53e..f9c00dd01e 100644 --- a/web/app/components/header/maintenance-notice.tsx +++ b/web/app/components/header/maintenance-notice.tsx @@ -1,11 +1,10 @@ import { useState } from 'react' -import { useContext } from 'use-context-selector' -import I18n from '@/context/i18n' import { X } from '@/app/components/base/icons/src/vender/line/general' import { NOTICE_I18N } from '@/i18n/language' +import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' const MaintenanceNotice = () => { - const { locale } = useContext(I18n) + const locale = useLanguage() const [showNotice, setShowNotice] = useState(localStorage.getItem('hide-maintenance-notice') !== '1') const handleJumpNotice = () => { From de9c7f2ea44b55191a01e1c4148e201f72392f4d Mon Sep 17 00:00:00 2001 From: geosmart Date: Thu, 5 Jun 2025 12:11:11 +0800 Subject: [PATCH 66/73] Update template.zh.mdx-fix document update metadata body param (#20659) --- web/app/(commonLayout)/datasets/template/template.zh.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/(commonLayout)/datasets/template/template.zh.mdx b/web/app/(commonLayout)/datasets/template/template.zh.mdx index 08ef5d562a..d121a93df2 100644 --- a/web/app/(commonLayout)/datasets/template/template.zh.mdx +++ b/web/app/(commonLayout)/datasets/template/template.zh.mdx @@ -2223,7 +2223,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, PropertyInstructi - document_id (string) 文档 ID - metadata_list (list) 元数据列表 - id (string) 元数据 ID - - type (string) 元数据类型 + - value (string) 元数据值 - name (string) 元数据名称 From d608be6e7f17c60109cf0d7f53ce1892ffac5aff Mon Sep 17 00:00:00 2001 From: GuanMu Date: Thu, 5 Jun 2025 13:35:32 +0800 Subject: [PATCH 67/73] Add vscode debugger (#20668) --- .gitignore | 7 ++-- .vscode/README.md | 14 ++++++++ .vscode/launch.json.template | 68 ++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 .vscode/README.md create mode 100644 .vscode/launch.json.template diff --git a/.gitignore b/.gitignore index 8818ab6f65..74a9ef63ef 100644 --- a/.gitignore +++ b/.gitignore @@ -192,12 +192,12 @@ sdks/python-client/dist sdks/python-client/dify_client.egg-info .vscode/* -!.vscode/launch.json +!.vscode/launch.json.template +!.vscode/README.md pyrightconfig.json api/.vscode .idea/ -.vscode # pnpm /.pnpm-store @@ -207,3 +207,6 @@ plugins.jsonl # mise mise.toml + +# Next.js build output +.next/ diff --git a/.vscode/README.md b/.vscode/README.md new file mode 100644 index 0000000000..26516f0540 --- /dev/null +++ b/.vscode/README.md @@ -0,0 +1,14 @@ +# Debugging with VS Code + +This `launch.json.template` file provides various debug configurations for the Dify project within VS Code / Cursor. To use these configurations, you should copy the contents of this file into a new file named `launch.json` in the same `.vscode` directory. + +## How to Use + +1. **Create `launch.json`**: If you don't have one, create a file named `launch.json` inside the `.vscode` directory. +2. **Copy Content**: Copy the entire content from `launch.json.template` into your newly created `launch.json` file. +3. **Select Debug Configuration**: Go to the Run and Debug view in VS Code / Cursor (Ctrl+Shift+D or Cmd+Shift+D). +4. **Start Debugging**: Select the desired configuration from the dropdown menu and click the green play button. + +## Tips + +- If you need to debug with Edge browser instead of Chrome, modify the `serverReadyAction` configuration in the "Next.js: debug full stack" section, change `"debugWithChrome"` to `"debugWithEdge"` to use Microsoft Edge for debugging. diff --git a/.vscode/launch.json.template b/.vscode/launch.json.template new file mode 100644 index 0000000000..f5a7f0893b --- /dev/null +++ b/.vscode/launch.json.template @@ -0,0 +1,68 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Flask API", + "type": "debugpy", + "request": "launch", + "module": "flask", + "env": { + "FLASK_APP": "app.py", + "FLASK_ENV": "development", + "GEVENT_SUPPORT": "True" + }, + "args": [ + "run", + "--host=0.0.0.0", + "--port=5001", + "--no-debugger", + "--no-reload" + ], + "jinja": true, + "justMyCode": true, + "cwd": "${workspaceFolder}/api", + "python": "${workspaceFolder}/api/.venv/bin/python" + }, + { + "name": "Python: Celery Worker (Solo)", + "type": "debugpy", + "request": "launch", + "module": "celery", + "env": { + "GEVENT_SUPPORT": "True" + }, + "args": [ + "-A", + "app.celery", + "worker", + "-P", + "solo", + "-c", + "1", + "-Q", + "dataset,generation,mail,ops_trace", + "--loglevel", + "INFO" + ], + "justMyCode": false, + "cwd": "${workspaceFolder}/api", + "python": "${workspaceFolder}/api/.venv/bin/python" + }, + { + "name": "Next.js: debug full stack", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/web/node_modules/next/dist/bin/next", + "runtimeArgs": ["--inspect"], + "skipFiles": ["/**"], + "serverReadyAction": { + "action": "debugWithChrome", + "killOnServerStop": true, + "pattern": "- Local:.+(https?://.+)", + "uriFormat": "%s", + "webRoot": "${workspaceFolder}/web" + }, + "cwd": "${workspaceFolder}/web" + } + ] +} From 3367d4258d75079afc3e505b909184945adfa535 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Jun 2025 13:35:40 +0800 Subject: [PATCH 68/73] chore: translate i18n files (#20664) Co-authored-by: douxc <7553076+douxc@users.noreply.github.com> --- web/i18n/de-DE/app.ts | 2 ++ web/i18n/de-DE/share-app.ts | 3 +++ web/i18n/es-ES/app.ts | 2 ++ web/i18n/es-ES/common.ts | 1 + web/i18n/es-ES/share-app.ts | 3 +++ web/i18n/fa-IR/app.ts | 2 ++ web/i18n/fa-IR/share-app.ts | 3 +++ web/i18n/fr-FR/app.ts | 3 +++ web/i18n/fr-FR/share-app.ts | 3 +++ web/i18n/hi-IN/app.ts | 2 ++ web/i18n/hi-IN/share-app.ts | 3 +++ web/i18n/it-IT/app.ts | 2 ++ web/i18n/it-IT/share-app.ts | 3 +++ web/i18n/ko-KR/app.ts | 2 ++ web/i18n/ko-KR/share-app.ts | 3 +++ web/i18n/pl-PL/app.ts | 2 ++ web/i18n/pl-PL/share-app.ts | 3 +++ web/i18n/pt-BR/app.ts | 2 ++ web/i18n/pt-BR/share-app.ts | 3 +++ web/i18n/ro-RO/app.ts | 2 ++ web/i18n/ro-RO/share-app.ts | 3 +++ web/i18n/ru-RU/app.ts | 2 ++ web/i18n/ru-RU/share-app.ts | 3 +++ web/i18n/sl-SI/app.ts | 2 ++ web/i18n/sl-SI/share-app.ts | 3 +++ web/i18n/th-TH/app.ts | 2 ++ web/i18n/th-TH/share-app.ts | 3 +++ web/i18n/tr-TR/app.ts | 2 ++ web/i18n/tr-TR/share-app.ts | 3 +++ web/i18n/uk-UA/app.ts | 2 ++ web/i18n/uk-UA/share-app.ts | 3 +++ web/i18n/vi-VN/app.ts | 2 ++ web/i18n/vi-VN/share-app.ts | 3 +++ web/i18n/zh-Hant/app.ts | 2 ++ web/i18n/zh-Hant/share-app.ts | 3 +++ 35 files changed, 87 insertions(+) diff --git a/web/i18n/de-DE/app.ts b/web/i18n/de-DE/app.ts index b9fdde58ff..1373dd611b 100644 --- a/web/i18n/de-DE/app.ts +++ b/web/i18n/de-DE/app.ts @@ -220,12 +220,14 @@ const translation = { anyone: 'Jeder kann auf die Webanwendung zugreifen.', specific: 'Nur bestimmte Gruppen oder Mitglieder können auf die Webanwendung zugreifen.', organization: 'Jeder in der Organisation kann auf die Webanwendung zugreifen.', + external: 'Nur authentifizierte externe Benutzer können auf die Webanwendung zugreifen.', }, accessControlDialog: { accessItems: { anyone: 'Jeder mit dem Link', specific: 'Spezifische Gruppen oder Mitglieder', organization: 'Nur Mitglieder innerhalb des Unternehmens', + external: 'Authentifizierte externe Benutzer', }, operateGroupAndMember: { searchPlaceholder: 'Gruppen und Mitglieder suchen', diff --git a/web/i18n/de-DE/share-app.ts b/web/i18n/de-DE/share-app.ts index 462286fa23..33c40917dd 100644 --- a/web/i18n/de-DE/share-app.ts +++ b/web/i18n/de-DE/share-app.ts @@ -77,6 +77,9 @@ const translation = { executions: '{{num}} HINRICHTUNGEN', execution: 'AUSFÜHRUNG', }, + login: { + backToHome: 'Zurück zur Startseite', + }, } export default translation diff --git a/web/i18n/es-ES/app.ts b/web/i18n/es-ES/app.ts index c183485294..c1147720e7 100644 --- a/web/i18n/es-ES/app.ts +++ b/web/i18n/es-ES/app.ts @@ -212,12 +212,14 @@ const translation = { anyone: 'Cualquiera puede acceder a la aplicación web.', specific: 'Solo grupos o miembros específicos pueden acceder a la aplicación web', organization: 'Cualquiera en la organización puede acceder a la aplicación web', + external: 'Solo los usuarios externos autenticados pueden acceder a la aplicación web.', }, accessControlDialog: { accessItems: { anyone: 'Cualquiera con el enlace', specific: 'Grupos o miembros específicos', organization: 'Solo miembros dentro de la empresa', + external: 'Usuarios externos autenticados', }, operateGroupAndMember: { searchPlaceholder: 'Buscar grupos y miembros', diff --git a/web/i18n/es-ES/common.ts b/web/i18n/es-ES/common.ts index 22c70f6bff..82ed315f1c 100644 --- a/web/i18n/es-ES/common.ts +++ b/web/i18n/es-ES/common.ts @@ -654,6 +654,7 @@ const translation = { auto: 'sistema', light: 'luz', theme: 'Tema', + dark: 'noche', }, compliance: { iso27001: 'Certificación ISO 27001:2022', diff --git a/web/i18n/es-ES/share-app.ts b/web/i18n/es-ES/share-app.ts index 41aa35c43e..caeb056d89 100644 --- a/web/i18n/es-ES/share-app.ts +++ b/web/i18n/es-ES/share-app.ts @@ -77,6 +77,9 @@ const translation = { execution: 'EJECUCIÓN', executions: '{{num}} EJECUCIONES', }, + login: { + backToHome: 'Volver a Inicio', + }, } export default translation diff --git a/web/i18n/fa-IR/app.ts b/web/i18n/fa-IR/app.ts index d37f4e8f90..13473d21f5 100644 --- a/web/i18n/fa-IR/app.ts +++ b/web/i18n/fa-IR/app.ts @@ -213,12 +213,14 @@ const translation = { specific: 'فقط گروه‌ها یا اعضای خاصی می‌توانند به اپلیکیشن وب دسترسی پیدا کنند.', anyone: 'هر کسی می‌تواند به وب‌اپلیکیشن دسترسی پیدا کند', organization: 'هر کسی در سازمان می‌تواند به اپلیکیشن وب دسترسی پیدا کند.', + external: 'تنها کاربران خارجی تأیید شده می‌توانند به برنامه وب دسترسی پیدا کنند.', }, accessControlDialog: { accessItems: { specific: 'گروه‌ها یا اعضای خاص', organization: 'فقط اعضای داخل سازمان', anyone: 'هر کسی که لینک را داشته باشد', + external: 'کاربران خارجی تأیید شده', }, operateGroupAndMember: { searchPlaceholder: 'گروه‌ها و اعضا را جستجو کنید', diff --git a/web/i18n/fa-IR/share-app.ts b/web/i18n/fa-IR/share-app.ts index bf1c0dec50..03ed4e8ea9 100644 --- a/web/i18n/fa-IR/share-app.ts +++ b/web/i18n/fa-IR/share-app.ts @@ -73,6 +73,9 @@ const translation = { executions: '{{num}} اعدام', execution: 'اجرا', }, + login: { + backToHome: 'بازگشت به خانه', + }, } export default translation diff --git a/web/i18n/fr-FR/app.ts b/web/i18n/fr-FR/app.ts index ffa00c758a..5c0965815e 100644 --- a/web/i18n/fr-FR/app.ts +++ b/web/i18n/fr-FR/app.ts @@ -207,17 +207,20 @@ const translation = { modelNotSupported: 'Modèle non pris en charge', moreFillTip: 'Affichage d\'un maximum de 10 niveaux d\'imbrication', configure: 'Configurer', + structured: 'systématique', }, accessItemsDescription: { anyone: 'Tout le monde peut accéder à l\'application web.', specific: 'Seules des groupes ou membres spécifiques peuvent accéder à l\'application web.', organization: 'Toute personne dans l\'organisation peut accéder à l\'application web.', + external: 'Seuls les utilisateurs externes authentifiés peuvent accéder à l\'application Web.', }, accessControlDialog: { accessItems: { anyone: 'Quiconque avec le lien', specific: 'Groupes ou membres spécifiques', organization: 'Seuls les membres au sein de l\'entreprise', + external: 'Utilisateurs externes authentifiés', }, operateGroupAndMember: { searchPlaceholder: 'Rechercher des groupes et des membres', diff --git a/web/i18n/fr-FR/share-app.ts b/web/i18n/fr-FR/share-app.ts index d0b3a5047e..2374da70e6 100644 --- a/web/i18n/fr-FR/share-app.ts +++ b/web/i18n/fr-FR/share-app.ts @@ -77,6 +77,9 @@ const translation = { executions: '{{num}} EXÉCUTIONS', execution: 'EXÉCUTION', }, + login: { + backToHome: 'Retour à l\'accueil', + }, } export default translation diff --git a/web/i18n/hi-IN/app.ts b/web/i18n/hi-IN/app.ts index f9486b93ec..3929dfeb6a 100644 --- a/web/i18n/hi-IN/app.ts +++ b/web/i18n/hi-IN/app.ts @@ -213,12 +213,14 @@ const translation = { anyone: 'कोई भी वेब ऐप तक पहुँच सकता है', organization: 'संस्थान के किसी भी व्यक्ति को वेब ऐप तक पहुंच प्राप्त है', specific: 'केवल विशेष समूह या सदस्य ही वेब ऐप तक पहुंच सकते हैं', + external: 'केवल प्रमाणित बाहरी उपयोगकर्ता वेब अनुप्रयोग तक पहुँच सकते हैं', }, accessControlDialog: { accessItems: { anyone: 'लिंक के साथ कोई भी', specific: 'विशिष्ट समूह या सदस्य', organization: 'केवल उद्यम के भीतर के सदस्य', + external: 'प्रमाणित बाहरी उपयोगकर्ता', }, operateGroupAndMember: { searchPlaceholder: 'समूहों और सदस्यों की खोज करें', diff --git a/web/i18n/hi-IN/share-app.ts b/web/i18n/hi-IN/share-app.ts index e0296fda83..a1e716b5bc 100644 --- a/web/i18n/hi-IN/share-app.ts +++ b/web/i18n/hi-IN/share-app.ts @@ -80,6 +80,9 @@ const translation = { execution: 'अनु执行', executions: '{{num}} फाँसी', }, + login: { + backToHome: 'होम पर वापस', + }, } export default translation diff --git a/web/i18n/it-IT/app.ts b/web/i18n/it-IT/app.ts index f6855873db..2bd5069b6c 100644 --- a/web/i18n/it-IT/app.ts +++ b/web/i18n/it-IT/app.ts @@ -224,12 +224,14 @@ const translation = { anyone: 'Chiunque può accedere all\'app web', specific: 'Solo gruppi o membri specifici possono accedere all\'app web.', organization: 'Qualsiasi persona nell\'organizzazione può accedere all\'app web', + external: 'Solo gli utenti esterni autenticati possono accedere all\'applicazione Web', }, accessControlDialog: { accessItems: { anyone: 'Chiunque con il link', specific: 'Gruppi o membri specifici', organization: 'Solo i membri all\'interno dell\'impresa', + external: 'Utenti esterni autenticati', }, operateGroupAndMember: { searchPlaceholder: 'Cerca gruppi e membri', diff --git a/web/i18n/it-IT/share-app.ts b/web/i18n/it-IT/share-app.ts index 2e1c96a396..4c6c18ff33 100644 --- a/web/i18n/it-IT/share-app.ts +++ b/web/i18n/it-IT/share-app.ts @@ -79,6 +79,9 @@ const translation = { execution: 'ESECUZIONE', executions: '{{num}} ESECUZIONI', }, + login: { + backToHome: 'Torna alla home', + }, } export default translation diff --git a/web/i18n/ko-KR/app.ts b/web/i18n/ko-KR/app.ts index 0ab08251fb..7227fd3171 100644 --- a/web/i18n/ko-KR/app.ts +++ b/web/i18n/ko-KR/app.ts @@ -209,12 +209,14 @@ const translation = { anyone: '누구나 웹 앱에 접근할 수 있습니다.', specific: '특정 그룹이나 회원만 웹 앱에 접근할 수 있습니다.', organization: '조직 내 모든 사람이 웹 애플리케이션에 접근할 수 있습니다.', + external: '인증된 외부 사용자만 웹 애플리케이션에 접근할 수 있습니다.', }, accessControlDialog: { accessItems: { anyone: '링크가 있는 누구나', specific: '특정 그룹 또는 구성원', organization: '기업 내의 회원만', + external: '인증된 외부 사용자', }, operateGroupAndMember: { searchPlaceholder: '그룹 및 구성원 검색', diff --git a/web/i18n/ko-KR/share-app.ts b/web/i18n/ko-KR/share-app.ts index 1ee44f2816..3958b4f93e 100644 --- a/web/i18n/ko-KR/share-app.ts +++ b/web/i18n/ko-KR/share-app.ts @@ -73,6 +73,9 @@ const translation = { execution: '실행', executions: '{{num}} 처형', }, + login: { + backToHome: '홈으로 돌아가기', + }, } export default translation diff --git a/web/i18n/pl-PL/app.ts b/web/i18n/pl-PL/app.ts index 54759154ca..856a64c868 100644 --- a/web/i18n/pl-PL/app.ts +++ b/web/i18n/pl-PL/app.ts @@ -220,12 +220,14 @@ const translation = { anyone: 'Każdy może uzyskać dostęp do aplikacji webowej', specific: 'Tylko określone grupy lub członkowie mogą uzyskać dostęp do aplikacji internetowej', organization: 'Każdy w organizacji ma dostęp do aplikacji internetowej.', + external: 'Tylko uwierzytelnieni zewnętrzni użytkownicy mogą uzyskać dostęp do aplikacji internetowej.', }, accessControlDialog: { accessItems: { anyone: 'Każdy z linkiem', specific: 'Specyficzne grupy lub członkowie', organization: 'Tylko członkowie w obrębie przedsiębiorstwa', + external: 'Uwierzytelnieni użytkownicy zewnętrzni', }, operateGroupAndMember: { searchPlaceholder: 'Szukaj grup i członków', diff --git a/web/i18n/pl-PL/share-app.ts b/web/i18n/pl-PL/share-app.ts index 80619cf4fc..617f66d994 100644 --- a/web/i18n/pl-PL/share-app.ts +++ b/web/i18n/pl-PL/share-app.ts @@ -78,6 +78,9 @@ const translation = { executions: '{{num}} EGZEKUCJI', execution: 'WYKONANIE', }, + login: { + backToHome: 'Powrót do strony głównej', + }, } export default translation diff --git a/web/i18n/pt-BR/app.ts b/web/i18n/pt-BR/app.ts index 5dd1753cac..766053456a 100644 --- a/web/i18n/pt-BR/app.ts +++ b/web/i18n/pt-BR/app.ts @@ -213,12 +213,14 @@ const translation = { anyone: 'Qualquer pessoa pode acessar o aplicativo web', specific: 'Apenas grupos ou membros específicos podem acessar o aplicativo web', organization: 'Qualquer pessoa na organização pode acessar o aplicativo web', + external: 'Apenas usuários externos autenticados podem acessar o aplicativo Web.', }, accessControlDialog: { accessItems: { anyone: 'Qualquer pessoa com o link', specific: 'Grupos específicos ou membros', organization: 'Apenas membros dentro da empresa', + external: 'Usuários externos autenticados', }, operateGroupAndMember: { searchPlaceholder: 'Pesquisar grupos e membros', diff --git a/web/i18n/pt-BR/share-app.ts b/web/i18n/pt-BR/share-app.ts index d8bca03089..9a9d7db632 100644 --- a/web/i18n/pt-BR/share-app.ts +++ b/web/i18n/pt-BR/share-app.ts @@ -77,6 +77,9 @@ const translation = { executions: '{{num}} EXECUÇÕES', execution: 'EXECUÇÃO', }, + login: { + backToHome: 'Voltar para a página inicial', + }, } export default translation diff --git a/web/i18n/ro-RO/app.ts b/web/i18n/ro-RO/app.ts index adf82aa38e..cd267e7b66 100644 --- a/web/i18n/ro-RO/app.ts +++ b/web/i18n/ro-RO/app.ts @@ -213,12 +213,14 @@ const translation = { specific: 'Numai grupuri sau membri specifici pot accesa aplicația web.', organization: 'Oricine din organizație poate accesa aplicația web', anyone: 'Oricine poate accesa aplicația web', + external: 'Numai utilizatorii externi autentificați pot accesa aplicația web', }, accessControlDialog: { accessItems: { anyone: 'Oricine are linkul', specific: 'Grupuri sau membri specifici', organization: 'Numai membrii din cadrul întreprinderii', + external: 'Utilizatori extern autentificați', }, operateGroupAndMember: { searchPlaceholder: 'Caută grupuri și membri', diff --git a/web/i18n/ro-RO/share-app.ts b/web/i18n/ro-RO/share-app.ts index 2cb39a0485..41e38812c5 100644 --- a/web/i18n/ro-RO/share-app.ts +++ b/web/i18n/ro-RO/share-app.ts @@ -77,6 +77,9 @@ const translation = { execution: 'EXECUȚIE', executions: '{{num}} EXECUȚII', }, + login: { + backToHome: 'Înapoi la Acasă', + }, } export default translation diff --git a/web/i18n/ru-RU/app.ts b/web/i18n/ru-RU/app.ts index fa73e33197..428d4c4e57 100644 --- a/web/i18n/ru-RU/app.ts +++ b/web/i18n/ru-RU/app.ts @@ -213,12 +213,14 @@ const translation = { anyone: 'Любой может получить доступ к веб-приложению', specific: 'Только определенные группы или участники могут получить доступ к веб-приложению.', organization: 'Любой в организации может получить доступ к веб-приложению', + external: 'Только аутентифицированные внешние пользователи могут получить доступ к веб-приложению.', }, accessControlDialog: { accessItems: { anyone: 'Кто угодно с ссылкой', specific: 'Конкретные группы или члены', organization: 'Только члены внутри предприятия', + external: 'Аутентифицированные внешние пользователи', }, operateGroupAndMember: { searchPlaceholder: 'Искать группы и участников', diff --git a/web/i18n/ru-RU/share-app.ts b/web/i18n/ru-RU/share-app.ts index b2850fa276..dafbe9d6b1 100644 --- a/web/i18n/ru-RU/share-app.ts +++ b/web/i18n/ru-RU/share-app.ts @@ -77,6 +77,9 @@ const translation = { execution: 'ИСПОЛНЕНИЕ', executions: '{{num}} ВЫПОЛНЕНИЯ', }, + login: { + backToHome: 'Назад на главную', + }, } export default translation diff --git a/web/i18n/sl-SI/app.ts b/web/i18n/sl-SI/app.ts index 6241d40f30..4ac445872d 100644 --- a/web/i18n/sl-SI/app.ts +++ b/web/i18n/sl-SI/app.ts @@ -213,12 +213,14 @@ const translation = { anyone: 'Vsakdo lahko dostopa do spletne aplikacije', specific: 'Samo določenim skupinam ali članom je omogočen dostop do spletne aplikacije', organization: 'Vsakdo v organizaciji lahko dostopa do spletne aplikacije', + external: 'Samo avtentificirani zunanji uporabniki lahko dostopajo do spletne aplikacije.', }, accessControlDialog: { accessItems: { anyone: 'Kdorkoli s povezavo', specific: 'Specifične skupine ali člani', organization: 'Samo člani znotraj podjetja', + external: 'Avtorizirani zunanji uporabniki', }, operateGroupAndMember: { searchPlaceholder: 'Išči skupine in člane', diff --git a/web/i18n/sl-SI/share-app.ts b/web/i18n/sl-SI/share-app.ts index 28d62b2336..8b7fe87cbd 100644 --- a/web/i18n/sl-SI/share-app.ts +++ b/web/i18n/sl-SI/share-app.ts @@ -74,6 +74,9 @@ const translation = { execution: 'IZVEDBA', executions: '{{num}} IZVRŠITEV', }, + login: { + backToHome: 'Nazaj na začetno stran', + }, } export default translation diff --git a/web/i18n/th-TH/app.ts b/web/i18n/th-TH/app.ts index 9204c71d32..0979d07f51 100644 --- a/web/i18n/th-TH/app.ts +++ b/web/i18n/th-TH/app.ts @@ -209,12 +209,14 @@ const translation = { anyone: 'ใครก็สามารถเข้าถึงเว็บแอปได้', specific: 'สมาชิกหรือกลุ่มเฉพาะเท่านั้นที่สามารถเข้าถึงแอปเว็บได้', organization: 'ใครก็ได้ในองค์กรสามารถเข้าถึงแอปเว็บได้', + external: 'ผู้ใช้งานภายนอกที่ได้รับการยืนยันตัวตนเท่านั้นที่สามารถเข้าถึงแอปพลิเคชันเว็บได้', }, accessControlDialog: { accessItems: { specific: 'กลุ่มหรือสมาชิกเฉพาะ', organization: 'เฉพาะสมาชิกภายในองค์กร', anyone: 'ใครก็ตามที่มีลิงก์', + external: 'ผู้ใช้ภายนอกที่ได้รับการตรวจสอบแล้ว', }, operateGroupAndMember: { searchPlaceholder: 'ค้นหากลุ่มและสมาชิก', diff --git a/web/i18n/th-TH/share-app.ts b/web/i18n/th-TH/share-app.ts index fd4a8f386c..eca049b9a2 100644 --- a/web/i18n/th-TH/share-app.ts +++ b/web/i18n/th-TH/share-app.ts @@ -73,6 +73,9 @@ const translation = { execution: 'การดำเนินการ', executions: '{{num}} การประหารชีวิต', }, + login: { + backToHome: 'กลับไปที่หน้าแรก', + }, } export default translation diff --git a/web/i18n/tr-TR/app.ts b/web/i18n/tr-TR/app.ts index 995cc9c795..5e55ffa349 100644 --- a/web/i18n/tr-TR/app.ts +++ b/web/i18n/tr-TR/app.ts @@ -209,12 +209,14 @@ const translation = { anyone: 'Herkes web uygulamasına erişebilir', organization: 'Kuruluşta herkes web uygulamasına erişebilir.', specific: 'Sadece belirli gruplar veya üyeler web uygulamasına erişebilir.', + external: 'Sadece kimliği doğrulanmış dış kullanıcılar Web uygulamasına erişebilir', }, accessControlDialog: { accessItems: { anyone: 'Bağlantıya sahip olan herkes', organization: 'Sadece işletme içindeki üyeler', specific: 'Belirli gruplar veya üyeler', + external: 'Kimliği onaylanmış harici kullanıcılar', }, operateGroupAndMember: { searchPlaceholder: 'Grupları ve üyeleri ara', diff --git a/web/i18n/tr-TR/share-app.ts b/web/i18n/tr-TR/share-app.ts index 184f44e147..e7ad4fcd68 100644 --- a/web/i18n/tr-TR/share-app.ts +++ b/web/i18n/tr-TR/share-app.ts @@ -73,6 +73,9 @@ const translation = { execution: 'İFRAZAT', executions: '{{num}} İDAM', }, + login: { + backToHome: 'Ana Sayfaya Dön', + }, } export default translation diff --git a/web/i18n/uk-UA/app.ts b/web/i18n/uk-UA/app.ts index 4bbb0dcbf1..6e5ff5dc74 100644 --- a/web/i18n/uk-UA/app.ts +++ b/web/i18n/uk-UA/app.ts @@ -213,12 +213,14 @@ const translation = { anyone: 'Будь-хто може отримати доступ до веб-додатку', specific: 'Тільки окремі групи або члени можуть отримати доступ до веб-додатку.', organization: 'Будь-хто в організації може отримати доступ до веб-додатку.', + external: 'Тільки перевірені зовнішні користувачі можуть отримати доступ до веб-застосунку.', }, accessControlDialog: { accessItems: { anyone: 'Кожен, у кого є посилання', specific: 'Конкретні групи або члени', organization: 'Тільки члени підприємства', + external: 'Аутентифіковані зовнішні користувачі', }, operateGroupAndMember: { searchPlaceholder: 'Шукати групи та учасників', diff --git a/web/i18n/uk-UA/share-app.ts b/web/i18n/uk-UA/share-app.ts index 058925ff15..92f25545d9 100644 --- a/web/i18n/uk-UA/share-app.ts +++ b/web/i18n/uk-UA/share-app.ts @@ -73,6 +73,9 @@ const translation = { execution: 'ВИКОНАННЯ', executions: '{{num}} ВИКОНАНЬ', }, + login: { + backToHome: 'Повернутися на головну', + }, } export default translation diff --git a/web/i18n/vi-VN/app.ts b/web/i18n/vi-VN/app.ts index 243454d011..c5f1a7496d 100644 --- a/web/i18n/vi-VN/app.ts +++ b/web/i18n/vi-VN/app.ts @@ -213,12 +213,14 @@ const translation = { anyone: 'Mọi người đều có thể truy cập ứng dụng web.', specific: 'Chỉ những nhóm hoặc thành viên cụ thể mới có thể truy cập ứng dụng web.', organization: 'Bất kỳ ai trong tổ chức đều có thể truy cập ứng dụng web.', + external: 'Chỉ những người dùng bên ngoài đã xác thực mới có thể truy cập vào ứng dụng Web.', }, accessControlDialog: { accessItems: { anyone: 'Ai có liên kết', specific: 'Các nhóm hoặc thành viên cụ thể', organization: 'Chỉ các thành viên trong doanh nghiệp', + external: 'Người dùng bên ngoài được xác thực', }, operateGroupAndMember: { searchPlaceholder: 'Tìm kiếm nhóm và thành viên', diff --git a/web/i18n/vi-VN/share-app.ts b/web/i18n/vi-VN/share-app.ts index a55f9b8476..12a31bd40b 100644 --- a/web/i18n/vi-VN/share-app.ts +++ b/web/i18n/vi-VN/share-app.ts @@ -73,6 +73,9 @@ const translation = { executions: '{{num}} ÁN TỬ HÌNH', execution: 'THI HÀNH', }, + login: { + backToHome: 'Trở về Trang Chủ', + }, } export default translation diff --git a/web/i18n/zh-Hant/app.ts b/web/i18n/zh-Hant/app.ts index c393fc949e..c43b2ee308 100644 --- a/web/i18n/zh-Hant/app.ts +++ b/web/i18n/zh-Hant/app.ts @@ -212,12 +212,14 @@ const translation = { anyone: '任何人都可以訪問這個網絡應用程式', specific: '只有特定的群體或成員可以訪問這個網絡應用程序', organization: '組織中的任何人都可以訪問該網絡應用程序', + external: '只有經過身份驗證的外部用戶才能訪問該網絡應用程序', }, accessControlDialog: { accessItems: { anyone: '擁有鏈接的人', specific: '特定群體或成員', organization: '只有企業內部成員', + external: '經過驗證的外部用戶', }, operateGroupAndMember: { searchPlaceholder: '搜尋群組和成員', diff --git a/web/i18n/zh-Hant/share-app.ts b/web/i18n/zh-Hant/share-app.ts index 54d2ff98b6..e25aa0c0de 100644 --- a/web/i18n/zh-Hant/share-app.ts +++ b/web/i18n/zh-Hant/share-app.ts @@ -73,6 +73,9 @@ const translation = { execution: '執行', executions: '{{num}} 執行', }, + login: { + backToHome: '返回首頁', + }, } export default translation From 837f769960932b67bf1157bdbe1e0c682ea5e177 Mon Sep 17 00:00:00 2001 From: minglu7 <1347866672@qq.com> Date: Thu, 5 Jun 2025 14:33:24 +0800 Subject: [PATCH 69/73] fix: update text_to_audio method to send data as JSON (#20663) --- sdks/python-client/dify_client/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdks/python-client/dify_client/client.py b/sdks/python-client/dify_client/client.py index ee1b5c57e1..d885dc6fb7 100644 --- a/sdks/python-client/dify_client/client.py +++ b/sdks/python-client/dify_client/client.py @@ -47,7 +47,7 @@ class DifyClient: def text_to_audio(self, text: str, user: str, streaming: bool = False): data = {"text": text, "user": user, "streaming": streaming} - return self._send_request("POST", "/text-to-audio", data=data) + return self._send_request("POST", "/text-to-audio", json=data) def get_meta(self, user): params = {"user": user} From 0ccf8cb23ebcffd097b6fbee86200239f771473e Mon Sep 17 00:00:00 2001 From: Novice <857526207@qq.com> Date: Thu, 5 Jun 2025 14:56:41 +0800 Subject: [PATCH 70/73] fix: agent moderation not working (#20673) --- web/app/components/base/chat/chat/hooks.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/components/base/chat/chat/hooks.ts b/web/app/components/base/chat/chat/hooks.ts index 28f297b90e..10fb455d33 100644 --- a/web/app/components/base/chat/chat/hooks.ts +++ b/web/app/components/base/chat/chat/hooks.ts @@ -366,7 +366,7 @@ export const useChat = ( if (!newResponseItem) return - const isUseAgentThought = newResponseItem.agent_thoughts?.length > 0 + const isUseAgentThought = newResponseItem.agent_thoughts?.length > 0 && newResponseItem.agent_thoughts[newResponseItem.agent_thoughts?.length - 1].thought === newResponseItem.answer updateChatTreeNode(responseItem.id, { content: isUseAgentThought ? '' : newResponseItem.answer, log: [ From 3fb9b41fe52472812cb64fd04b6c85b02b8efb90 Mon Sep 17 00:00:00 2001 From: HaiyangP <46739135+HaiyangPeng@users.noreply.github.com> Date: Thu, 5 Jun 2025 14:59:55 +0800 Subject: [PATCH 71/73] A more concise and effective extractor for excel and csv files (#20625) Co-authored-by: haiyangpengai --- .../workflow/nodes/document_extractor/node.py | 44 +++++- .../nodes/test_document_extractor_node.py | 140 +++++++----------- 2 files changed, 92 insertions(+), 92 deletions(-) diff --git a/api/core/workflow/nodes/document_extractor/node.py b/api/core/workflow/nodes/document_extractor/node.py index d39eb9c932..429fed2d04 100644 --- a/api/core/workflow/nodes/document_extractor/node.py +++ b/api/core/workflow/nodes/document_extractor/node.py @@ -397,19 +397,44 @@ def _extract_text_from_csv(file_content: bytes) -> str: if not rows: return "" + # Combine multi-line text in the header row + header_row = [cell.replace("\n", " ").replace("\r", "") for cell in rows[0]] + # Create Markdown table - markdown_table = "| " + " | ".join(rows[0]) + " |\n" - markdown_table += "| " + " | ".join(["---"] * len(rows[0])) + " |\n" + markdown_table = "| " + " | ".join(header_row) + " |\n" + markdown_table += "| " + " | ".join(["-" * len(col) for col in rows[0]]) + " |\n" + + # Process each data row and combine multi-line text in each cell for row in rows[1:]: - markdown_table += "| " + " | ".join(row) + " |\n" + processed_row = [cell.replace("\n", " ").replace("\r", "") for cell in row] + markdown_table += "| " + " | ".join(processed_row) + " |\n" - return markdown_table.strip() + return markdown_table except Exception as e: raise TextExtractionError(f"Failed to extract text from CSV: {str(e)}") from e def _extract_text_from_excel(file_content: bytes) -> str: """Extract text from an Excel file using pandas.""" + + def _construct_markdown_table(df: pd.DataFrame) -> str: + """Manually construct a Markdown table from a DataFrame.""" + # Construct the header row + header_row = "| " + " | ".join(df.columns) + " |" + + # Construct the separator row + separator_row = "| " + " | ".join(["-" * len(col) for col in df.columns]) + " |" + + # Construct the data rows + data_rows = [] + for _, row in df.iterrows(): + data_row = "| " + " | ".join(map(str, row)) + " |" + data_rows.append(data_row) + + # Combine all rows into a single string + markdown_table = "\n".join([header_row, separator_row] + data_rows) + return markdown_table + try: excel_file = pd.ExcelFile(io.BytesIO(file_content)) markdown_table = "" @@ -417,8 +442,15 @@ def _extract_text_from_excel(file_content: bytes) -> str: try: df = excel_file.parse(sheet_name=sheet_name) df.dropna(how="all", inplace=True) - # Create Markdown table two times to separate tables with a newline - markdown_table += df.to_markdown(index=False, floatfmt="") + "\n\n" + + # Combine multi-line text in each cell into a single line + df = df.applymap(lambda x: " ".join(str(x).splitlines()) if isinstance(x, str) else x) # type: ignore + + # Combine multi-line text in column names into a single line + df.columns = pd.Index([" ".join(col.splitlines()) for col in df.columns]) + + # Manually construct the Markdown table + markdown_table += _construct_markdown_table(df) + "\n\n" except Exception as e: continue return markdown_table diff --git a/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py b/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py index 35d83449c3..4cb1aa93f9 100644 --- a/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py +++ b/api/tests/unit_tests/core/workflow/nodes/test_document_extractor_node.py @@ -1,5 +1,7 @@ +import io from unittest.mock import Mock, patch +import pandas as pd import pytest from docx.oxml.text.paragraph import CT_P @@ -187,145 +189,134 @@ def test_node_type(document_extractor_node): @patch("pandas.ExcelFile") def test_extract_text_from_excel_single_sheet(mock_excel_file): - """Test extracting text from Excel file with single sheet.""" - # Mock DataFrame - mock_df = Mock() - mock_df.dropna = Mock() - mock_df.to_markdown.return_value = "| Name | Age |\n|------|-----|\n| John | 25 |" + """Test extracting text from Excel file with single sheet and multiline content.""" + + # Test multi-line cell + data = {"Name\nwith\nnewline": ["John\nDoe", "Jane\nSmith"], "Age": [25, 30]} + + df = pd.DataFrame(data) # Mock ExcelFile mock_excel_instance = Mock() mock_excel_instance.sheet_names = ["Sheet1"] - mock_excel_instance.parse.return_value = mock_df + mock_excel_instance.parse.return_value = df mock_excel_file.return_value = mock_excel_instance file_content = b"fake_excel_content" result = _extract_text_from_excel(file_content) + expected_manual = "| Name with newline | Age |\n| ----------------- | --- |\n\ +| John Doe | 25 |\n| Jane Smith | 30 |\n\n" - expected = "| Name | Age |\n|------|-----|\n| John | 25 |\n\n" - assert result == expected - mock_excel_file.assert_called_once() - mock_df.dropna.assert_called_once_with(how="all", inplace=True) - mock_df.to_markdown.assert_called_once_with(index=False, floatfmt="") + assert expected_manual == result + mock_excel_instance.parse.assert_called_once_with(sheet_name="Sheet1") @patch("pandas.ExcelFile") def test_extract_text_from_excel_multiple_sheets(mock_excel_file): - """Test extracting text from Excel file with multiple sheets.""" - # Mock DataFrames for different sheets - mock_df1 = Mock() - mock_df1.dropna = Mock() - mock_df1.to_markdown.return_value = "| Product | Price |\n|---------|-------|\n| Apple | 1.50 |" + """Test extracting text from Excel file with multiple sheets and multiline content.""" - mock_df2 = Mock() - mock_df2.dropna = Mock() - mock_df2.to_markdown.return_value = "| City | Population |\n|------|------------|\n| NYC | 8000000 |" + # Test multi-line cell + data1 = {"Product\nName": ["Apple\nRed", "Banana\nYellow"], "Price": [1.50, 0.99]} + df1 = pd.DataFrame(data1) + + data2 = {"City\nName": ["New\nYork", "Los\nAngeles"], "Population": [8000000, 3900000]} + df2 = pd.DataFrame(data2) # Mock ExcelFile mock_excel_instance = Mock() mock_excel_instance.sheet_names = ["Products", "Cities"] - mock_excel_instance.parse.side_effect = [mock_df1, mock_df2] + mock_excel_instance.parse.side_effect = [df1, df2] mock_excel_file.return_value = mock_excel_instance file_content = b"fake_excel_content_multiple_sheets" result = _extract_text_from_excel(file_content) - expected = ( - "| Product | Price |\n|---------|-------|\n| Apple | 1.50 |\n\n" - "| City | Population |\n|------|------------|\n| NYC | 8000000 |\n\n" - ) - assert result == expected + expected_manual1 = "| Product Name | Price |\n| ------------ | ----- |\n\ +| Apple Red | 1.5 |\n| Banana Yellow | 0.99 |\n\n" + expected_manual2 = "| City Name | Population |\n| --------- | ---------- |\n\ +| New York | 8000000 |\n| Los Angeles | 3900000 |\n\n" + + assert expected_manual1 in result + assert expected_manual2 in result + assert mock_excel_instance.parse.call_count == 2 @patch("pandas.ExcelFile") def test_extract_text_from_excel_empty_sheets(mock_excel_file): """Test extracting text from Excel file with empty sheets.""" - # Mock empty DataFrame - mock_df = Mock() - mock_df.dropna = Mock() - mock_df.to_markdown.return_value = "" + + # Empty excel + df = pd.DataFrame() # Mock ExcelFile mock_excel_instance = Mock() mock_excel_instance.sheet_names = ["EmptySheet"] - mock_excel_instance.parse.return_value = mock_df + mock_excel_instance.parse.return_value = df mock_excel_file.return_value = mock_excel_instance file_content = b"fake_excel_empty_content" result = _extract_text_from_excel(file_content) - expected = "\n\n" + expected = "| |\n| |\n\n" assert result == expected + mock_excel_instance.parse.assert_called_once_with(sheet_name="EmptySheet") + @patch("pandas.ExcelFile") def test_extract_text_from_excel_sheet_parse_error(mock_excel_file): """Test handling of sheet parsing errors - should continue with other sheets.""" - # Mock DataFrames - one successful, one that raises exception - mock_df_success = Mock() - mock_df_success.dropna = Mock() - mock_df_success.to_markdown.return_value = "| Data | Value |\n|------|-------|\n| Test | 123 |" + + # Test error + data = {"Data": ["Test"], "Value": [123]} + df = pd.DataFrame(data) # Mock ExcelFile mock_excel_instance = Mock() mock_excel_instance.sheet_names = ["GoodSheet", "BadSheet"] - mock_excel_instance.parse.side_effect = [mock_df_success, Exception("Parse error")] + mock_excel_instance.parse.side_effect = [df, Exception("Parse error")] mock_excel_file.return_value = mock_excel_instance file_content = b"fake_excel_mixed_content" result = _extract_text_from_excel(file_content) - expected = "| Data | Value |\n|------|-------|\n| Test | 123 |\n\n" - assert result == expected - - -@patch("pandas.ExcelFile") -def test_extract_text_from_excel_file_error(mock_excel_file): - """Test handling of Excel file reading errors.""" - mock_excel_file.side_effect = Exception("Invalid Excel file") - - file_content = b"invalid_excel_content" + expected_manual = "| Data | Value |\n| ---- | ----- |\n| Test | 123 |\n\n" - with pytest.raises(Exception) as exc_info: - _extract_text_from_excel(file_content) + assert expected_manual == result - # Note: The function should raise TextExtractionError, but since it's not imported in the test, - # we check for the general Exception pattern - assert "Failed to extract text from Excel file" in str(exc_info.value) + assert mock_excel_instance.parse.call_count == 2 @patch("pandas.ExcelFile") def test_extract_text_from_excel_io_bytesio_usage(mock_excel_file): """Test that BytesIO is properly used with the file content.""" - import io - # Mock DataFrame - mock_df = Mock() - mock_df.dropna = Mock() - mock_df.to_markdown.return_value = "| Test | Data |\n|------|------|\n| 1 | A |" + # Test bytesio + data = {"Test": [1], "Data": ["A"]} + df = pd.DataFrame(data) # Mock ExcelFile mock_excel_instance = Mock() mock_excel_instance.sheet_names = ["TestSheet"] - mock_excel_instance.parse.return_value = mock_df + mock_excel_instance.parse.return_value = df mock_excel_file.return_value = mock_excel_instance file_content = b"test_excel_bytes" result = _extract_text_from_excel(file_content) - # Verify that ExcelFile was called with a BytesIO object mock_excel_file.assert_called_once() - call_args = mock_excel_file.call_args[0][0] - assert isinstance(call_args, io.BytesIO) + call_arg = mock_excel_file.call_args[0][0] + assert isinstance(call_arg, io.BytesIO) - expected = "| Test | Data |\n|------|------|\n| 1 | A |\n\n" - assert result == expected + expected_manual = "| Test | Data |\n| ---- | ---- |\n| 1 | A |\n\n" + assert expected_manual == result @patch("pandas.ExcelFile") def test_extract_text_from_excel_all_sheets_fail(mock_excel_file): """Test when all sheets fail to parse - should return empty string.""" + # Mock ExcelFile mock_excel_instance = Mock() mock_excel_instance.sheet_names = ["BadSheet1", "BadSheet2"] @@ -335,29 +326,6 @@ def test_extract_text_from_excel_all_sheets_fail(mock_excel_file): file_content = b"fake_excel_all_bad_sheets" result = _extract_text_from_excel(file_content) - # Should return empty string when all sheets fail assert result == "" - -@patch("pandas.ExcelFile") -def test_extract_text_from_excel_markdown_formatting(mock_excel_file): - """Test that markdown formatting parameters are correctly applied.""" - # Mock DataFrame - mock_df = Mock() - mock_df.dropna = Mock() - mock_df.to_markdown.return_value = "| Float | Int |\n|-------|-----|\n| 123456.78 | 42 |" - - # Mock ExcelFile - mock_excel_instance = Mock() - mock_excel_instance.sheet_names = ["NumberSheet"] - mock_excel_instance.parse.return_value = mock_df - mock_excel_file.return_value = mock_excel_instance - - file_content = b"fake_excel_numbers" - result = _extract_text_from_excel(file_content) - - # Verify to_markdown was called with correct parameters - mock_df.to_markdown.assert_called_once_with(index=False, floatfmt="") - - expected = "| Float | Int |\n|-------|-----|\n| 123456.78 | 42 |\n\n" - assert result == expected + assert mock_excel_instance.parse.call_count == 2 From a02a4199ff6072b21970b15d0760aed0fe061c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adem=C3=ADlson=20Tonato?= Date: Fri, 30 May 2025 15:16:39 +0100 Subject: [PATCH 72/73] feat: add search endpoint for Firecrawl Integration --- .../rag/extractor/firecrawl/firecrawl_app.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/api/core/rag/extractor/firecrawl/firecrawl_app.py b/api/core/rag/extractor/firecrawl/firecrawl_app.py index 836a1398bf..16d713b47c 100644 --- a/api/core/rag/extractor/firecrawl/firecrawl_app.py +++ b/api/core/rag/extractor/firecrawl/firecrawl_app.py @@ -127,3 +127,29 @@ class FirecrawlApp: def _handle_error(self, response, action) -> None: error_message = response.json().get("error", "Unknown error occurred") raise Exception(f"Failed to {action}. Status code: {response.status_code}. Error: {error_message}") + + def search(self, query: str, params: dict[str, Any] | None = None) -> dict[str, Any]: + # Documentation: https://docs.firecrawl.dev/api-reference/endpoint/search + headers = self._prepare_headers() + json_data = { + "query": query, + "limit": 5, + "lang": "en", + "country": "us", + "timeout": 60000, + "ignoreInvalidURLs": False, + "scrapeOptions": {}, + } + if params: + json_data.update(params) + response = self._post_request(f"{self.base_url}/v1/search", json_data, headers) + if response.status_code == 200: + response_data = response.json() + if not response_data.get("success"): + raise Exception(f"Search failed. Error: {response_data.get('warning', 'Unknown error')}") + return response_data + elif response.status_code in {402, 409, 500, 429, 408}: + self._handle_error(response, "perform search") + return {} # Avoid additional exception after handling error + else: + raise Exception(f"Failed to perform search. Status code: {response.status_code}") From 84576f1675d91e24d10476ca987517a78d06c18e Mon Sep 17 00:00:00 2001 From: crazywoola <427733928@qq.com> Date: Thu, 5 Jun 2025 15:28:52 +0800 Subject: [PATCH 73/73] fix: lint --- api/core/rag/extractor/firecrawl/firecrawl_app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/core/rag/extractor/firecrawl/firecrawl_app.py b/api/core/rag/extractor/firecrawl/firecrawl_app.py index 16d713b47c..3ac63daf63 100644 --- a/api/core/rag/extractor/firecrawl/firecrawl_app.py +++ b/api/core/rag/extractor/firecrawl/firecrawl_app.py @@ -150,6 +150,5 @@ class FirecrawlApp: return response_data elif response.status_code in {402, 409, 500, 429, 408}: self._handle_error(response, "perform search") - return {} # Avoid additional exception after handling error else: raise Exception(f"Failed to perform search. Status code: {response.status_code}")
{t('datasetDocuments.list.batchModal.contentTitle')}{t('datasetDocuments.list.batchModal.contentTitle')}
{t('datasetDocuments.list.batchModal.content')} 1{t('datasetDocuments.list.batchModal.content')} 1
{t('datasetDocuments.list.batchModal.content')} 2