From 20f0238aabe932e69248454bf9f3540f234f1c3d Mon Sep 17 00:00:00 2001 From: qiaofenlin Date: Sun, 3 Aug 2025 16:27:12 +0800 Subject: [PATCH] feat: support workflow version specification in workflow and chat APIs (#23188) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- api/controllers/service_api/app/completion.py | 11 +- api/controllers/service_api/app/workflow.py | 57 ++++- api/services/app_generate_service.py | 25 +- api/services/errors/app.py | 8 + api/services/workflow_service.py | 5 +- .../template/template_advanced_chat.en.mdx | 6 + .../template/template_advanced_chat.ja.mdx | 6 + .../template/template_advanced_chat.zh.mdx | 6 + .../develop/template/template_chat.en.mdx | 6 + .../develop/template/template_chat.ja.mdx | 6 + .../develop/template/template_chat.zh.mdx | 6 + .../develop/template/template_workflow.en.mdx | 234 ++++++++++++++++++ .../develop/template/template_workflow.ja.mdx | 229 +++++++++++++++++ .../develop/template/template_workflow.zh.mdx | 229 +++++++++++++++++ .../context-menu/use-context-menu.ts | 7 +- .../panel/version-history-panel/index.tsx | 10 +- .../version-history-item.tsx | 1 - web/app/components/workflow/types.ts | 1 + web/i18n/en-US/workflow.ts | 4 +- web/i18n/zh-Hans/workflow.ts | 2 + 20 files changed, 846 insertions(+), 13 deletions(-) diff --git a/api/controllers/service_api/app/completion.py b/api/controllers/service_api/app/completion.py index edc66cc5e..ea57f0485 100644 --- a/api/controllers/service_api/app/completion.py +++ b/api/controllers/service_api/app/completion.py @@ -2,7 +2,7 @@ import logging from flask import request from flask_restful import Resource, reqparse -from werkzeug.exceptions import InternalServerError, NotFound +from werkzeug.exceptions import BadRequest, InternalServerError, NotFound import services from controllers.service_api import api @@ -30,6 +30,7 @@ from libs import helper from libs.helper import uuid_value from models.model import App, AppMode, EndUser from services.app_generate_service import AppGenerateService +from services.errors.app import IsDraftWorkflowError, WorkflowIdFormatError, WorkflowNotFoundError from services.errors.llm import InvokeRateLimitError @@ -113,7 +114,7 @@ class ChatApi(Resource): parser.add_argument("conversation_id", type=uuid_value, location="json") parser.add_argument("retriever_from", type=str, required=False, default="dev", location="json") parser.add_argument("auto_generate_name", type=bool, required=False, default=True, location="json") - + parser.add_argument("workflow_id", type=str, required=False, location="json") args = parser.parse_args() external_trace_id = get_external_trace_id(request) @@ -128,6 +129,12 @@ class ChatApi(Resource): ) return helper.compact_generate_response(response) + except WorkflowNotFoundError as ex: + raise NotFound(str(ex)) + except IsDraftWorkflowError as ex: + raise BadRequest(str(ex)) + except WorkflowIdFormatError as ex: + raise BadRequest(str(ex)) except services.errors.conversation.ConversationNotExistsError: raise NotFound("Conversation Not Exists.") except services.errors.conversation.ConversationCompletedError: diff --git a/api/controllers/service_api/app/workflow.py b/api/controllers/service_api/app/workflow.py index 370ff911b..cd8a5f03a 100644 --- a/api/controllers/service_api/app/workflow.py +++ b/api/controllers/service_api/app/workflow.py @@ -5,7 +5,7 @@ from flask import request from flask_restful import Resource, fields, marshal_with, reqparse from flask_restful.inputs import int_range from sqlalchemy.orm import Session, sessionmaker -from werkzeug.exceptions import InternalServerError +from werkzeug.exceptions import BadRequest, InternalServerError, NotFound from controllers.service_api import api from controllers.service_api.app.error import ( @@ -34,6 +34,7 @@ from libs.helper import TimestampField from models.model import App, AppMode, EndUser from repositories.factory import DifyAPIRepositoryFactory from services.app_generate_service import AppGenerateService +from services.errors.app import IsDraftWorkflowError, WorkflowIdFormatError, WorkflowNotFoundError from services.errors.llm import InvokeRateLimitError from services.workflow_app_service import WorkflowAppService @@ -120,6 +121,59 @@ class WorkflowRunApi(Resource): raise InternalServerError() +class WorkflowRunByIdApi(Resource): + @validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True)) + def post(self, app_model: App, end_user: EndUser, workflow_id: str): + """ + Run specific workflow by ID + """ + app_mode = AppMode.value_of(app_model.mode) + if app_mode != AppMode.WORKFLOW: + raise NotWorkflowAppError() + + parser = reqparse.RequestParser() + parser.add_argument("inputs", type=dict, required=True, nullable=False, location="json") + parser.add_argument("files", type=list, required=False, location="json") + parser.add_argument("response_mode", type=str, choices=["blocking", "streaming"], location="json") + args = parser.parse_args() + + # Add workflow_id to args for AppGenerateService + args["workflow_id"] = workflow_id + + external_trace_id = get_external_trace_id(request) + if external_trace_id: + args["external_trace_id"] = external_trace_id + streaming = args.get("response_mode") == "streaming" + + try: + response = AppGenerateService.generate( + app_model=app_model, user=end_user, args=args, invoke_from=InvokeFrom.SERVICE_API, streaming=streaming + ) + + return helper.compact_generate_response(response) + except WorkflowNotFoundError as ex: + raise NotFound(str(ex)) + except IsDraftWorkflowError as ex: + raise BadRequest(str(ex)) + except WorkflowIdFormatError as ex: + raise BadRequest(str(ex)) + except ProviderTokenNotInitError as ex: + raise ProviderNotInitializeError(ex.description) + except QuotaExceededError: + raise ProviderQuotaExceededError() + except ModelCurrentlyNotSupportError: + raise ProviderModelCurrentlyNotSupportError() + except InvokeRateLimitError as ex: + raise InvokeRateLimitHttpError(ex.description) + except InvokeError as e: + raise CompletionRequestError(e.description) + except ValueError as e: + raise e + except Exception: + logging.exception("internal server error.") + raise InternalServerError() + + class WorkflowTaskStopApi(Resource): @validate_app_token(fetch_user_arg=FetchUserArg(fetch_from=WhereisUserArg.JSON, required=True)) def post(self, app_model: App, end_user: EndUser, task_id: str): @@ -193,5 +247,6 @@ class WorkflowAppLogApi(Resource): api.add_resource(WorkflowRunApi, "/workflows/run") api.add_resource(WorkflowRunDetailApi, "/workflows/run/") +api.add_resource(WorkflowRunByIdApi, "/workflows//run") api.add_resource(WorkflowTaskStopApi, "/workflows/tasks//stop") api.add_resource(WorkflowAppLogApi, "/workflows/logs") diff --git a/api/services/app_generate_service.py b/api/services/app_generate_service.py index 6f7e705b5..6792324ec 100644 --- a/api/services/app_generate_service.py +++ b/api/services/app_generate_service.py @@ -1,5 +1,6 @@ +import uuid from collections.abc import Generator, Mapping -from typing import Any, Union +from typing import Any, Optional, Union from openai._exceptions import RateLimitError @@ -15,6 +16,7 @@ from libs.helper import RateLimiter from models.model import Account, App, AppMode, EndUser from models.workflow import Workflow from services.billing_service import BillingService +from services.errors.app import WorkflowIdFormatError, WorkflowNotFoundError from services.errors.llm import InvokeRateLimitError from services.workflow_service import WorkflowService @@ -86,7 +88,8 @@ class AppGenerateService: request_id=request_id, ) elif app_model.mode == AppMode.ADVANCED_CHAT.value: - workflow = cls._get_workflow(app_model, invoke_from) + workflow_id = args.get("workflow_id") + workflow = cls._get_workflow(app_model, invoke_from, workflow_id) return rate_limit.generate( AdvancedChatAppGenerator.convert_to_event_stream( AdvancedChatAppGenerator().generate( @@ -101,7 +104,8 @@ class AppGenerateService: request_id=request_id, ) elif app_model.mode == AppMode.WORKFLOW.value: - workflow = cls._get_workflow(app_model, invoke_from) + workflow_id = args.get("workflow_id") + workflow = cls._get_workflow(app_model, invoke_from, workflow_id) return rate_limit.generate( WorkflowAppGenerator.convert_to_event_stream( WorkflowAppGenerator().generate( @@ -210,14 +214,27 @@ class AppGenerateService: ) @classmethod - def _get_workflow(cls, app_model: App, invoke_from: InvokeFrom) -> Workflow: + def _get_workflow(cls, app_model: App, invoke_from: InvokeFrom, workflow_id: Optional[str] = None) -> Workflow: """ Get workflow :param app_model: app model :param invoke_from: invoke from + :param workflow_id: optional workflow id to specify a specific version :return: """ workflow_service = WorkflowService() + + # If workflow_id is specified, get the specific workflow version + if workflow_id: + try: + workflow_uuid = uuid.UUID(workflow_id) + except ValueError: + raise WorkflowIdFormatError(f"Invalid workflow_id format: '{workflow_id}'. ") + workflow = workflow_service.get_published_workflow_by_id(app_model=app_model, workflow_id=workflow_id) + if not workflow: + raise WorkflowNotFoundError(f"Workflow not found with id: {workflow_id}") + return workflow + if invoke_from == InvokeFrom.DEBUGGER: # fetch draft workflow by app_model workflow = workflow_service.get_draft_workflow(app_model=app_model) diff --git a/api/services/errors/app.py b/api/services/errors/app.py index 5d348c61b..390716a47 100644 --- a/api/services/errors/app.py +++ b/api/services/errors/app.py @@ -8,3 +8,11 @@ class WorkflowHashNotEqualError(Exception): class IsDraftWorkflowError(Exception): pass + + +class WorkflowNotFoundError(Exception): + pass + + +class WorkflowIdFormatError(Exception): + pass diff --git a/api/services/workflow_service.py b/api/services/workflow_service.py index 858814498..0c5d29b78 100644 --- a/api/services/workflow_service.py +++ b/api/services/workflow_service.py @@ -129,7 +129,10 @@ class WorkflowService: if not workflow: return None if workflow.version == Workflow.VERSION_DRAFT: - raise IsDraftWorkflowError(f"Workflow is draft version, id={workflow_id}") + raise IsDraftWorkflowError( + f"Cannot use draft workflow version. Workflow ID: {workflow_id}. " + f"Please use a published workflow version or leave workflow_id empty." + ) return workflow def get_published_workflow(self, app_model: App) -> Optional[Workflow]: diff --git a/web/app/components/develop/template/template_advanced_chat.en.mdx b/web/app/components/develop/template/template_advanced_chat.en.mdx index ba698bdfd..66c45b6e4 100644 --- a/web/app/components/develop/template/template_advanced_chat.en.mdx +++ b/web/app/components/develop/template/template_advanced_chat.en.mdx @@ -80,6 +80,9 @@ Chat applications support session persistence, allowing previous chat history to Auto-generate title, default is `true`. If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`. + + (Optional) Workflow ID to specify a specific version, if not provided, uses the default published version. + (Optional) Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority:
- Header: via HTTP Header X-Trace-Id, highest priority.
@@ -225,6 +228,9 @@ Chat applications support session persistence, allowing previous chat history to - 400, `provider_not_initialize`, no available model credential configuration - 400, `provider_quota_exceeded`, model invocation quota insufficient - 400, `model_currently_not_support`, current model unavailable + - 400, `workflow_not_found`, specified workflow version not found + - 400, `draft_workflow_error`, cannot use draft workflow version + - 400, `workflow_id_format_error`, invalid workflow_id format, expected UUID format - 400, `completion_request_error`, text generation failed - 500, internal server error diff --git a/web/app/components/develop/template/template_advanced_chat.ja.mdx b/web/app/components/develop/template/template_advanced_chat.ja.mdx index 5e9153ce1..849b58129 100644 --- a/web/app/components/develop/template/template_advanced_chat.ja.mdx +++ b/web/app/components/develop/template/template_advanced_chat.ja.mdx @@ -80,6 +80,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from タイトルを自動生成、デフォルトは`true`。 `false`に設定すると、会話のリネームAPIを呼び出し、`auto_generate`を`true`に設定することで非同期タイトル生成を実現できます。
+ + (オプション)ワークフローID、特定のバージョンを指定するために使用、提供されない場合はデフォルトの公開バージョンを使用。 + (オプション)トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:
- Header:HTTPヘッダー X-Trace-Id で渡す(最優先)。
@@ -225,6 +228,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - 400, `provider_not_initialize`, 利用可能なモデル資格情報構成がありません - 400, `provider_quota_exceeded`, モデル呼び出しクォータが不足しています - 400, `model_currently_not_support`, 現在のモデルが利用できません + - 400, `workflow_not_found`, 指定されたワークフローバージョンが見つかりません + - 400, `draft_workflow_error`, ドラフトワークフローバージョンは使用できません + - 400, `workflow_id_format_error`, ワークフローID形式エラー、UUID形式が必要です - 400, `completion_request_error`, テキスト生成に失敗しました - 500, 内部サーバーエラー 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 969edaa47..47c88bda9 100755 --- a/web/app/components/develop/template/template_advanced_chat.zh.mdx +++ b/web/app/components/develop/template/template_advanced_chat.zh.mdx @@ -78,6 +78,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' (选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。 + + (选填)工作流ID,用于指定特定版本,如果不提供则使用默认的已发布版本。 + (选填)链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统会自动生成trace_id。支持以下三种方式传递,具体优先级依次为:
- Header:通过 HTTP Header X-Trace-Id 传递,优先级最高。
@@ -224,6 +227,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' - 400,`provider_not_initialize`,无可用模型凭据配置 - 400,`provider_quota_exceeded`,模型调用额度不足 - 400,`model_currently_not_support`,当前模型不可用 + - 400,`workflow_not_found`,指定的工作流版本未找到 + - 400,`draft_workflow_error`,无法使用草稿工作流版本 + - 400,`workflow_id_format_error`,工作流ID格式错误,需要UUID格式 - 400,`completion_request_error`,文本生成失败 - 500,服务内部异常 diff --git a/web/app/components/develop/template/template_chat.en.mdx b/web/app/components/develop/template/template_chat.en.mdx index e357c7628..24efe62fd 100644 --- a/web/app/components/develop/template/template_chat.en.mdx +++ b/web/app/components/develop/template/template_chat.en.mdx @@ -74,6 +74,9 @@ Chat applications support session persistence, allowing previous chat history to Auto-generate title, default is `true`. If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`.
+ + (Optional) Workflow ID to specify a specific version, if not provided, uses the default published version. + (Optional) Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority:
- Header: via HTTP Header X-Trace-Id, highest priority.
@@ -180,6 +183,9 @@ Chat applications support session persistence, allowing previous chat history to - 400, `provider_not_initialize`, no available model credential configuration - 400, `provider_quota_exceeded`, model invocation quota insufficient - 400, `model_currently_not_support`, current model unavailable + - 400, `workflow_not_found`, specified workflow version not found + - 400, `draft_workflow_error`, cannot use draft workflow version + - 400, `workflow_id_format_error`, invalid workflow_id format, expected UUID format - 400, `completion_request_error`, text generation failed - 500, internal server error diff --git a/web/app/components/develop/template/template_chat.ja.mdx b/web/app/components/develop/template/template_chat.ja.mdx index 1e2ba63db..d251bcd5c 100644 --- a/web/app/components/develop/template/template_chat.ja.mdx +++ b/web/app/components/develop/template/template_chat.ja.mdx @@ -74,6 +74,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from タイトルを自動生成します。デフォルトは`true`です。 `false`に設定すると、会話のリネームAPIを呼び出し、`auto_generate`を`true`に設定することで非同期タイトル生成を実現できます。
+ + (オプション)ワークフローID、特定のバージョンを指定するために使用、提供されない場合はデフォルトの公開バージョンを使用。 + (オプション)トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:
- Header:HTTPヘッダー X-Trace-Id で渡す(最優先)。
@@ -180,6 +183,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from - 400, `provider_not_initialize`, 利用可能なモデル資格情報構成がありません - 400, `provider_quota_exceeded`, モデル呼び出しクォータが不足しています - 400, `model_currently_not_support`, 現在のモデルは利用できません + - 400, `workflow_not_found`, 指定されたワークフローバージョンが見つかりません + - 400, `draft_workflow_error`, ドラフトワークフローバージョンは使用できません + - 400, `workflow_id_format_error`, ワークフローID形式エラー、UUID形式が必要です - 400, `completion_request_error`, テキスト生成に失敗しました - 500, 内部サーバーエラー diff --git a/web/app/components/develop/template/template_chat.zh.mdx b/web/app/components/develop/template/template_chat.zh.mdx index e14032558..998d524b5 100644 --- a/web/app/components/develop/template/template_chat.zh.mdx +++ b/web/app/components/develop/template/template_chat.zh.mdx @@ -73,6 +73,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' (选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。 + + (选填)工作流ID,用于指定特定版本,如果不提供则使用默认的已发布版本。 + (选填)链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统会自动生成trace_id。支持以下三种方式传递,具体优先级依次为:
- Header:通过 HTTP Header X-Trace-Id 传递,优先级最高。
@@ -181,6 +184,9 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' - 400,`provider_not_initialize`,无可用模型凭据配置 - 400,`provider_quota_exceeded`,模型调用额度不足 - 400,`model_currently_not_support`,当前模型不可用 + - 400,`workflow_not_found`,指定的工作流版本未找到 + - 400,`draft_workflow_error`,无法使用草稿工作流版本 + - 400,`workflow_id_format_error`,工作流ID格式错误,需要UUID格式 - 400,`completion_request_error`,文本生成失败 - 500,服务内部异常 diff --git a/web/app/components/develop/template/template_workflow.en.mdx b/web/app/components/develop/template/template_workflow.en.mdx index 8ac1db328..19487a852 100644 --- a/web/app/components/develop/template/template_workflow.en.mdx +++ b/web/app/components/develop/template/template_workflow.en.mdx @@ -338,6 +338,240 @@ Workflow applications offers non-session support and is ideal for translation, a --- + + + + Execute a specific version of workflow by specifying the workflow ID in the path parameter. + + ### Path + - `workflow_id` (string) Required Workflow ID to specify a specific version of workflow + + How to obtain: In the version history interface, click the copy icon on the right side of each version entry to copy the complete workflow ID. Each version entry contains a copyable ID field. + + ### Request Body + - `inputs` (object) Required + Allows the entry of various variable values defined by the App. + The `inputs` parameter contains multiple key/value pairs, with each key corresponding to a specific variable and each value being the specific value for that variable. + The workflow application requires at least one key/value pair to be inputted. The variable can be of File Array type. + File Array type variable is suitable for inputting files combined with text understanding and answering questions, available only when the model supports file parsing and understanding capability. + If the variable is of File Array type, the corresponding value should be a list whose elements contain following attributions: + - `type` (string) Supported type: + - `document` ('TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB') + - `image` ('JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG') + - `audio` ('MP3', 'M4A', 'WAV', 'WEBM', 'AMR') + - `video` ('MP4', 'MOV', 'MPEG', 'MPGA') + - `custom` (Other file types) + - `transfer_method` (string) Transfer method, `remote_url` for image URL / `local_file` for file upload + - `url` (string) Image URL (when the transfer method is `remote_url`) + - `upload_file_id` (string) Uploaded file ID, which must be obtained by uploading through the File Upload API in advance (when the transfer method is `local_file`) + + - `response_mode` (string) Required + The mode of response return, supporting: + - `streaming` Streaming mode (recommended), implements a typewriter-like output through SSE ([Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)). + - `blocking` Blocking mode, returns result after execution is complete. (Requests may be interrupted if the process is long) + Due to Cloudflare restrictions, the request will be interrupted without a return after 100 seconds. + - `user` (string) Required + User identifier, used to define the identity of the end-user for retrieval and statistics. + Should be uniquely defined by the developer within the application. +
+ The user identifier should be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp. + - `files` (array[object]) Optional + - `trace_id` (string) Optional + Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority: + 1. Header: via HTTP Header `X-Trace-Id`, highest priority. + 2. Query parameter: via URL query parameter `trace_id`. + 3. Request Body: via request body field `trace_id` (i.e., this field). + + ### Response + When `response_mode` is `blocking`, return a CompletionResponse object. + When `response_mode` is `streaming`, return a ChunkCompletionResponse stream. + + ### CompletionResponse + Returns the App result, `Content-Type` is `application/json`. + - `workflow_run_id` (string) Unique ID of workflow execution + - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API + - `data` (object) detail of result + - `id` (string) ID of workflow execution + - `workflow_id` (string) ID of related workflow + - `status` (string) status of execution, `running` / `succeeded` / `failed` / `stopped` + - `outputs` (json) Optional content of output + - `error` (string) Optional reason of error + - `elapsed_time` (float) Optional total seconds to be used + - `total_tokens` (int) Optional tokens to be used + - `total_steps` (int) default 0 + - `created_at` (timestamp) start time + - `finished_at` (timestamp) end time + + ### ChunkCompletionResponse + Returns the stream chunks outputted by the App, `Content-Type` is `text/event-stream`. + Each streaming chunk starts with `data:`, separated by two newline characters `\n\n`, as shown below: + + ```streaming {{ title: 'Response' }} + 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 + ``` + + The structure of the streaming chunks varies depending on the `event`: + - `event: workflow_started` workflow starts execution + - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API + - `workflow_run_id` (string) Unique ID of workflow execution + - `event` (string) fixed to `workflow_started` + - `data` (object) detail + - `id` (string) Unique ID of workflow execution + - `workflow_id` (string) ID of related workflow + - `created_at` (timestamp) Creation timestamp, e.g., 1705395332 + - `event: node_started` node execution started + - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API + - `workflow_run_id` (string) Unique ID of workflow execution + - `event` (string) fixed to `node_started` + - `data` (object) detail + - `id` (string) Unique ID of workflow execution + - `node_id` (string) ID of node + - `node_type` (string) type of node + - `title` (string) name of node + - `index` (int) Execution sequence number, used to display Tracing Node sequence + - `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path + - `inputs` (object) Contents of all preceding node variables used in the node + - `created_at` (timestamp) timestamp of start, e.g., 1705395332 + - `event: text_chunk` Text fragment + - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API + - `workflow_run_id` (string) Unique ID of workflow execution + - `event` (string) fixed to `text_chunk` + - `data` (object) detail + - `text` (string) Text content + - `from_variable_selector` (array) Text source path, helps developers understand which variable of which node the text is generated from + - `event: node_finished` node execution finished, success and failure are different states in the same event + - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API + - `workflow_run_id` (string) Unique ID of workflow execution + - `event` (string) fixed to `node_finished` + - `data` (object) detail + - `id` (string) Unique ID of node execution + - `node_id` (string) ID of node + - `index` (int) Execution sequence number, used to display Tracing Node sequence + - `predecessor_node_id` (string) optional Prefix node ID, used for canvas display execution path + - `inputs` (object) Contents of all preceding node variables used in the node + - `process_data` (json) Optional Process data of node + - `outputs` (json) Optional content of output + - `status` (string) status of execution `running` / `succeeded` / `failed` / `stopped` + - `error` (string) Optional reason of error + - `elapsed_time` (float) Optional total seconds to be used + - `execution_metadata` (json) metadata + - `total_tokens` (int) optional tokens to be used + - `total_price` (decimal) optional total cost + - `currency` (string) optional currency, such as `USD` / `RMB` + - `created_at` (timestamp) timestamp of start, e.g., 1705395332 + - `event: workflow_finished` workflow execution finished, success and failure are different states in the same event + - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API + - `workflow_run_id` (string) Unique ID of workflow execution + - `event` (string) fixed to `workflow_finished` + - `data` (object) detail + - `id` (string) Unique ID of workflow execution + - `workflow_id` (string) ID of related workflow + - `status` (string) status of execution `running` / `succeeded` / `failed` / `stopped` + - `outputs` (json) Optional content of output + - `error` (string) Optional reason of error + - `elapsed_time` (float) Optional total seconds to be used + - `total_tokens` (int) Optional tokens to be used + - `total_steps` (int) default 0 + - `created_at` (timestamp) start time + - `finished_at` (timestamp) end time + - `event: tts_message` TTS audio stream event, i.e., speech synthesis output. The content is an audio block in Mp3 format, encoded as a base64 string, which can be decoded directly when playing. (Only available when auto-play is enabled) + - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API + - `message_id` (string) Unique message ID + - `audio` (string) The audio block after speech synthesis is encoded as base64 text content, which can be directly base64 decoded and sent to the player when playing + - `created_at` (int) Creation timestamp, e.g., 1705395332 + - `event: tts_message_end` TTS audio stream end event, receiving this event indicates the end of audio stream return. + - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API + - `message_id` (string) Unique message ID + - `audio` (string) The end event has no audio, so this is an empty string + - `created_at` (int) Creation timestamp, e.g., 1705395332 + - `event: ping` Ping event every 10s to keep the connection alive. + + ### Errors + - 400, `invalid_param`, Invalid input parameters + - 400, `app_unavailable`, App configuration unavailable + - 400, `provider_not_initialize`, No available model credentials configured + - 400, `provider_quota_exceeded`, Insufficient model call quota + - 400, `model_currently_not_support`, Current model unavailable + - 400, `workflow_not_found`, Specified workflow version not found + - 400, `draft_workflow_error`, Cannot use draft workflow version + - 400, `workflow_id_format_error`, Workflow ID format error, UUID format required + - 400, `workflow_request_error`, Workflow execution failed + - 500, Internal service error + + + + + ```bash {{ title: 'cURL' }} + curl -X POST '${props.appDetail.api_base_url}/workflows/{workflow_id}/run' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "inputs": {}, + "response_mode": "streaming", + "user": "abc-123" + }' + ``` + + + ```json {{ title: 'File variable example' }} + { + "inputs": { + "{variable_name}": + [ + { + "transfer_method": "local_file", + "upload_file_id": "{upload_file_id}", + "type": "{document_type}" + } + ] + } + } + ``` + + ### Blocking Mode + + ```json {{ title: 'Response' }} + { + "workflow_run_id": "djflajgkldjgd", + "task_id": "9da23599-e713-473b-982c-4328d4f5c78a", + "data": { + "id": "fdlsjfjejkghjda", + "workflow_id": "fldjaslkfjlsda", + "status": "succeeded", + "outputs": { + "text": "Nice to meet you." + }, + "error": null, + "elapsed_time": 0.875, + "total_tokens": 3562, + "total_steps": 8, + "created_at": 1705407629, + "finished_at": 1727807631 + } + } + ``` + + ### Streaming Mode + + ```streaming {{ title: 'Response' }} + data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} + data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} + data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} + data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} + data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"} + data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""} + ``` + + +
+ +--- + + + + パスパラメータでワークフローIDを指定して、特定バージョンのワークフローを実行します。 + + ### パス + - `workflow_id` (string) 必須 特定バージョンのワークフローを指定するためのワークフローID + + 取得方法:バージョン履歴で特定バージョンのワークフローIDを照会できます。 + + ### リクエストボディ + - `inputs` (object) 必須 + App で定義された各変数値を入力できます。 + inputs パラメータには複数のキー/値ペアが含まれており、各キーは特定の変数に対応し、各値はその変数の具体的な値です。変数はファイルリスト型にすることができます。 + ファイルリスト型変数は、ファイルをテキスト理解と組み合わせて質問に答えるために入力するのに適しており、モデルがファイル解析機能をサポートしている場合のみ使用できます。変数がファイルリスト型の場合、その変数に対応する値はリスト形式である必要があり、各要素には以下の内容が含まれます: + - `type` (string) サポートされるタイプ: + - `document` 具体的なタイプには以下が含まれます:'TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB' + - `image` 具体的なタイプには以下が含まれます:'JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG' + - `audio` 具体的なタイプには以下が含まれます:'MP3', 'M4A', 'WAV', 'WEBM', 'AMR' + - `video` 具体的なタイプには以下が含まれます:'MP4', 'MOV', 'MPEG', 'MPGA' + - `custom` 具体的なタイプには以下が含まれます:その他のファイルタイプ + - `transfer_method` (string) 転送方法、`remote_url` 画像URL / `local_file` ファイルアップロード + - `url` (string) 画像URL(転送方法が `remote_url` の場合のみ) + - `upload_file_id` (string) アップロードされたファイルID(転送方法が `local_file` の場合のみ) + - `response_mode` (string) 必須 + 応答返却モード、以下をサポート: + - `streaming` ストリーミングモード(推奨)。SSE(**[Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)**)をベースにタイプライター風の出力を実現。 + - `blocking` ブロッキングモード、実行完了後に結果を返却。(プロセスが長い場合、リクエストが中断される可能性があります)。 + Cloudflare の制限により、100秒後に応答がない場合、リクエストは中断されます。 + - `user` (string) 必須 + ユーザー識別子、エンドユーザーのアイデンティティを定義し、検索・統計を容易にするために使用されます。 + 開発者が定義するルールで、アプリケーション内でユーザー識別子が一意である必要があります。API は WebApp で作成されたセッションにアクセスできません。 + - `files` (array[object]) オプション + - `trace_id` (string) オプション + トレースID。既存のビジネスシステムのトレースコンポーネントと統合して、エンドツーエンドの分散トレーシングを実現するために使用されます。指定されていない場合、システムは自動的に `trace_id` を生成します。以下の3つの方法で渡すことができ、優先順位は以下の通りです: + 1. ヘッダー:HTTP ヘッダー `X-Trace-Id` で渡すことを推奨、最高優先度。 + 2. クエリパラメータ:URL クエリパラメータ `trace_id` で渡す。 + 3. リクエストボディ:リクエストボディフィールド `trace_id` で渡す(つまり、このフィールド)。 + + ### 応答 + `response_mode` が `blocking` の場合、CompletionResponse オブジェクトを返します。 + `response_mode` が `streaming` の場合、ChunkCompletionResponse オブジェクトのストリーミングシーケンスを返します。 + + ### CompletionResponse + 完全な App 結果を返し、`Content-Type` は `application/json` です。 + - `workflow_run_id` (string) ワークフロー実行ID + - `task_id` (string) タスクID、リクエスト追跡と以下の停止応答インターフェースに使用 + - `data` (object) 詳細内容 + - `id` (string) ワークフロー実行ID + - `workflow_id` (string) 関連するワークフローID + - `status` (string) 実行ステータス、`running` / `succeeded` / `failed` / `stopped` + - `outputs` (json) オプション 出力内容 + - `error` (string) オプション エラー理由 + - `elapsed_time` (float) オプション 使用時間(s) + - `total_tokens` (int) オプション 使用されるトークンの総数 + - `total_steps` (int) 総ステップ数(冗長)、デフォルト 0 + - `created_at` (timestamp) 開始時間 + - `finished_at` (timestamp) 終了時間 + + ### ChunkCompletionResponse + App の出力ストリーミングチャンクを返し、`Content-Type` は `text/event-stream` です。 + 各ストリーミングチャンクは `data:` で始まり、チャンク間は `\n\n` つまり2つの改行文字で区切られます。以下のようになります: + + ```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 + ``` + + ストリーミングチャンクは `event` によって構造が異なり、以下のタイプが含まれます: + - `event: workflow_started` ワークフロー実行開始 + - `task_id` (string) タスクID、リクエスト追跡と以下の停止応答インターフェースに使用 + - `workflow_run_id` (string) ワークフロー実行ID + - `event` (string) `workflow_started` に固定 + - `data` (object) 詳細内容 + - `id` (string) ワークフロー実行ID + - `workflow_id` (string) 関連するワークフローID + - `created_at` (timestamp) 開始時間 + - `event: node_started` ノード実行開始 + - `task_id` (string) タスクID、リクエスト追跡と以下の停止応答インターフェースに使用 + - `workflow_run_id` (string) ワークフロー実行ID + - `event` (string) `node_started` に固定 + - `data` (object) 詳細内容 + - `id` (string) ワークフロー実行ID + - `node_id` (string) ノードID + - `node_type` (string) ノードタイプ + - `title` (string) ノード名 + - `index` (int) 実行シーケンス番号、Tracing Node シーケンスの表示に使用 + - `predecessor_node_id` (string) 前置ノードID、キャンバス表示実行パスに使用 + - `inputs` (object) ノードで使用されるすべての前置ノード変数の内容 + - `created_at` (timestamp) 開始時間 + - `event: text_chunk` テキストフラグメント + - `task_id` (string) タスクID、リクエスト追跡と以下の停止応答インターフェースに使用 + - `workflow_run_id` (string) ワークフロー実行ID + - `event` (string) `text_chunk` に固定 + - `data` (object) 詳細内容 + - `text` (string) テキスト内容 + - `from_variable_selector` (array) テキストソースパス、開発者がテキストがどのノードのどの変数から生成されたかを理解するのに役立ちます + - `event: node_finished` ノード実行終了、成功と失敗は同じイベント内の異なる状態 + - `task_id` (string) タスクID、リクエスト追跡と以下の停止応答インターフェースに使用 + - `workflow_run_id` (string) ワークフロー実行ID + - `event` (string) `node_finished` に固定 + - `data` (object) 詳細内容 + - `id` (string) ノード実行ID + - `node_id` (string) ノードID + - `index` (int) 実行シーケンス番号、Tracing Node シーケンスの表示に使用 + - `predecessor_node_id` (string) オプション 前置ノードID、キャンバス表示実行パスに使用 + - `inputs` (object) ノードで使用されるすべての前置ノード変数の内容 + - `process_data` (json) オプション ノードプロセスデータ + - `outputs` (json) オプション 出力内容 + - `status` (string) 実行ステータス `running` / `succeeded` / `failed` / `stopped` + - `error` (string) オプション エラー理由 + - `elapsed_time` (float) オプション 使用時間(s) + - `execution_metadata` (json) メタデータ + - `total_tokens` (int) オプション 使用されるトークンの総数 + - `total_price` (decimal) オプション 総費用 + - `currency` (string) オプション 通貨、例:`USD` / `RMB` + - `created_at` (timestamp) 開始時間 + - `event: workflow_finished` ワークフロー実行終了、成功と失敗は同じイベント内の異なる状態 + - `task_id` (string) タスクID、リクエスト追跡と以下の停止応答インターフェースに使用 + - `workflow_run_id` (string) ワークフロー実行ID + - `event` (string) `workflow_finished` に固定 + - `data` (object) 詳細内容 + - `id` (string) ワークフロー実行ID + - `workflow_id` (string) 関連するワークフローID + - `status` (string) 実行ステータス `running` / `succeeded` / `failed` / `stopped` + - `outputs` (json) オプション 出力内容 + - `error` (string) オプション エラー理由 + - `elapsed_time` (float) オプション 使用時間(s) + - `total_tokens` (int) オプション 使用されるトークンの総数 + - `total_steps` (int) 総ステップ数(冗長)、デフォルト 0 + - `created_at` (timestamp) 開始時間 + - `finished_at` (timestamp) 終了時間 + - `event: tts_message` TTS オーディオストリームイベント、つまり:音声合成出力。内容はMp3形式のオーディオブロックで、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 + - `audio` (string) 終了イベントにはオーディオがないため、ここは空文字列です + - `created_at` (int) 作成タイムスタンプ、例:1705395332 + - `event: ping` 10秒ごとのpingイベント、接続を維持します。 + + ### エラー + - 400,`invalid_param`,入力パラメータ異常 + - 400,`app_unavailable`,App 設定が利用できません + - 400,`provider_not_initialize`,利用可能なモデル認証情報設定がありません + - 400,`provider_quota_exceeded`,モデル呼び出しクォータが不足しています + - 400,`model_currently_not_support`,現在のモデルが利用できません + - 400,`workflow_not_found`,指定されたワークフローバージョンが見つかりません + - 400,`draft_workflow_error`,ドラフトワークフローバージョンを使用できません + - 400,`workflow_id_format_error`,ワークフローID形式エラー、UUID形式が必要です + - 400,`workflow_request_error`,ワークフロー実行に失敗しました + - 500,サービス内部異常 + + + + + ```bash {{ title: 'cURL' }} + curl -X POST '${props.appDetail.api_base_url}/workflows/{workflow_id}/run' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "inputs": {}, + "response_mode": "streaming", + "user": "abc-123" + }' + ``` + + + ```json {{ title: 'ファイル変数の例' }} + { + "inputs": { + "{variable_name}": + [ + { + "transfer_method": "local_file", + "upload_file_id": "{upload_file_id}", + "type": "{document_type}" + } + ] + } + } + ``` + + ### ブロッキングモード + + ```json {{ title: '応答' }} + { + "workflow_run_id": "djflajgkldjgd", + "task_id": "9da23599-e713-473b-982c-4328d4f5c78a", + "data": { + "id": "fdlsjfjejkghjda", + "workflow_id": "fldjaslkfjlsda", + "status": "succeeded", + "outputs": { + "text": "Nice to meet you." + }, + "error": null, + "elapsed_time": 0.875, + "total_tokens": 3562, + "total_steps": 8, + "created_at": 1705407629, + "finished_at": 1727807631 + } + } + ``` + + ### ストリーミングモード + + ```streaming {{ title: '応答' }} + data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} + data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} + data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} + data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} + data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"} + data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""} + ``` + + + + +--- + + + + 执行指定版本的工作流,通过路径参数指定工作流ID。 + + ### Path + - `workflow_id` (string) Required 工作流ID,用于指定特定版本的工作流 + + 获取方式:可以在版本历史中查询特定版本的工作流ID。 + + ### Request Body + - `inputs` (object) Required + 允许传入 App 定义的各变量值。 + inputs 参数包含了多组键值对(Key/Value pairs),每组的键对应一个特定变量,每组的值则是该变量的具体值。变量可以是文件列表类型。 + 文件列表类型变量适用于传入文件结合文本理解并回答问题,仅当模型支持该类型文件解析能力时可用。如果该变量是文件列表类型,该变量对应的值应是列表格式,其中每个元素应包含以下内容: + - `type` (string) 支持类型: + - `document` 具体类型包含:'TXT', 'MD', 'MARKDOWN', 'PDF', 'HTML', 'XLSX', 'XLS', 'DOCX', 'CSV', 'EML', 'MSG', 'PPTX', 'PPT', 'XML', 'EPUB' + - `image` 具体类型包含:'JPG', 'JPEG', 'PNG', 'GIF', 'WEBP', 'SVG' + - `audio` 具体类型包含:'MP3', 'M4A', 'WAV', 'WEBM', 'AMR' + - `video` 具体类型包含:'MP4', 'MOV', 'MPEG', 'MPGA' + - `custom` 具体类型包含:其他文件类型 + - `transfer_method` (string) 传递方式,`remote_url` 图片地址 / `local_file` 上传文件 + - `url` (string) 图片地址(仅当传递方式为 `remote_url` 时) + - `upload_file_id` (string) 上传文件 ID(仅当传递方式为 `local_file` 时) + - `response_mode` (string) Required + 返回响应模式,支持: + - `streaming` 流式模式(推荐)。基于 SSE(**[Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)**)实现类似打字机输出方式的流式返回。 + - `blocking` 阻塞模式,等待执行完毕后返回结果。(请求若流程较长可能会被中断)。 + 由于 Cloudflare 限制,请求会在 100 秒超时无返回后中断。 + - `user` (string) Required + 用户标识,用于定义终端用户的身份,方便检索、统计。 + 由开发者定义规则,需保证用户标识在应用内唯一。API 无法访问 WebApp 创建的会话。 + - `files` (array[object]) 可选 + - `trace_id` (string) Optional + 链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统将自动生成 `trace_id`。支持以下三种方式传递,具体优先级依次为: + 1. Header:推荐通过 HTTP Header `X-Trace-Id` 传递,优先级最高。 + 2. Query 参数:通过 URL 查询参数 `trace_id` 传递。 + 3. Request Body:通过请求体字段 `trace_id` 传递(即本字段)。 + + ### Response + 当 `response_mode` 为 `blocking` 时,返回 CompletionResponse object。 + 当 `response_mode` 为 `streaming`时,返回 ChunkCompletionResponse object 流式序列。 + + ### CompletionResponse + 返回完整的 App 结果,`Content-Type` 为 `application/json` 。 + - `workflow_run_id` (string) workflow 执行 ID + - `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口 + - `data` (object) 详细内容 + - `id` (string) workflow 执行 ID + - `workflow_id` (string) 关联 Workflow ID + - `status` (string) 执行状态, `running` / `succeeded` / `failed` / `stopped` + - `outputs` (json) Optional 输出内容 + - `error` (string) Optional 错误原因 + - `elapsed_time` (float) Optional 耗时(s) + - `total_tokens` (int) Optional 总使用 tokens + - `total_steps` (int) 总步数(冗余),默认 0 + - `created_at` (timestamp) 开始时间 + - `finished_at` (timestamp) 结束时间 + + ### ChunkCompletionResponse + 返回 App 输出的流式块,`Content-Type` 为 `text/event-stream`。 + 每个流式块均为 data: 开头,块之间以 `\n\n` 即两个换行符分隔,如下所示: + + ```streaming {{ title: 'Response' }} + 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 + ``` + + 流式块中根据 `event` 不同,结构也不同,包含以下类型: + - `event: workflow_started` workflow 开始执行 + - `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口 + - `workflow_run_id` (string) workflow 执行 ID + - `event` (string) 固定为 `workflow_started` + - `data` (object) 详细内容 + - `id` (string) workflow 执行 ID + - `workflow_id` (string) 关联 Workflow ID + - `created_at` (timestamp) 开始时间 + - `event: node_started` node 开始执行 + - `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口 + - `workflow_run_id` (string) workflow 执行 ID + - `event` (string) 固定为 `node_started` + - `data` (object) 详细内容 + - `id` (string) workflow 执行 ID + - `node_id` (string) 节点 ID + - `node_type` (string) 节点类型 + - `title` (string) 节点名称 + - `index` (int) 执行序号,用于展示 Tracing Node 顺序 + - `predecessor_node_id` (string) 前置节点 ID,用于画布展示执行路径 + - `inputs` (object) 节点中所有使用到的前置节点变量内容 + - `created_at` (timestamp) 开始时间 + - `event: text_chunk` 文本片段 + - `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口 + - `workflow_run_id` (string) workflow 执行 ID + - `event` (string) 固定为 `text_chunk` + - `data` (object) 详细内容 + - `text` (string) 文本内容 + - `from_variable_selector` (array) 文本来源路径,帮助开发者了解文本是由哪个节点的哪个变量生成的 + - `event: node_finished` node 执行结束,成功失败同一事件中不同状态 + - `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口 + - `workflow_run_id` (string) workflow 执行 ID + - `event` (string) 固定为 `node_finished` + - `data` (object) 详细内容 + - `id` (string) node 执行 ID + - `node_id` (string) 节点 ID + - `index` (int) 执行序号,用于展示 Tracing Node 顺序 + - `predecessor_node_id` (string) optional 前置节点 ID,用于画布展示执行路径 + - `inputs` (object) 节点中所有使用到的前置节点变量内容 + - `process_data` (json) Optional 节点过程数据 + - `outputs` (json) Optional 输出内容 + - `status` (string) 执行状态 `running` / `succeeded` / `failed` / `stopped` + - `error` (string) Optional 错误原因 + - `elapsed_time` (float) Optional 耗时(s) + - `execution_metadata` (json) 元数据 + - `total_tokens` (int) optional 总使用 tokens + - `total_price` (decimal) optional 总费用 + - `currency` (string) optional 货币,如 `USD` / `RMB` + - `created_at` (timestamp) 开始时间 + - `event: workflow_finished` workflow 执行结束,成功失败同一事件中不同状态 + - `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口 + - `workflow_run_id` (string) workflow 执行 ID + - `event` (string) 固定为 `workflow_finished` + - `data` (object) 详细内容 + - `id` (string) workflow 执行 ID + - `workflow_id` (string) 关联 Workflow ID + - `status` (string) 执行状态 `running` / `succeeded` / `failed` / `stopped` + - `outputs` (json) Optional 输出内容 + - `error` (string) Optional 错误原因 + - `elapsed_time` (float) Optional 耗时(s) + - `total_tokens` (int) Optional 总使用 tokens + - `total_steps` (int) 总步数(冗余),默认 0 + - `created_at` (timestamp) 开始时间 + - `finished_at` (timestamp) 结束时间 + - `event: tts_message` TTS 音频流事件,即:语音合成输出。内容是Mp3格式的音频块,使用 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 + - `audio` (string) 结束事件是没有音频的,所以这里是空字符串 + - `created_at` (int) 创建时间戳,如:1705395332 + - `event: ping` 每 10s 一次的 ping 事件,保持连接存活。 + + ### Errors + - 400,`invalid_param`,传入参数异常 + - 400,`app_unavailable`,App 配置不可用 + - 400,`provider_not_initialize`,无可用模型凭据配置 + - 400,`provider_quota_exceeded`,模型调用额度不足 + - 400,`model_currently_not_support`,当前模型不可用 + - 400,`workflow_not_found`,指定的工作流版本未找到 + - 400,`draft_workflow_error`,无法使用草稿工作流版本 + - 400,`workflow_id_format_error`,工作流ID格式错误,需要UUID格式 + - 400,`workflow_request_error`,workflow 执行失败 + - 500,服务内部异常 + + + + + ```bash {{ title: 'cURL' }} + curl -X POST '${props.appDetail.api_base_url}/workflows/{workflow_id}/run' \ + --header 'Authorization: Bearer {api_key}' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "inputs": {}, + "response_mode": "streaming", + "user": "abc-123" + }' + ``` + + + ```json {{ title: 'File variable example' }} + { + "inputs": { + "{variable_name}": + [ + { + "transfer_method": "local_file", + "upload_file_id": "{upload_file_id}", + "type": "{document_type}" + } + ] + } + } + ``` + + ### Blocking Mode + + ```json {{ title: 'Response' }} + { + "workflow_run_id": "djflajgkldjgd", + "task_id": "9da23599-e713-473b-982c-4328d4f5c78a", + "data": { + "id": "fdlsjfjejkghjda", + "workflow_id": "fldjaslkfjlsda", + "status": "succeeded", + "outputs": { + "text": "Nice to meet you." + }, + "error": null, + "elapsed_time": 0.875, + "total_tokens": 3562, + "total_steps": 8, + "created_at": 1705407629, + "finished_at": 1727807631 + } + } + ``` + + ### Streaming Mode + + ```streaming {{ title: 'Response' }} + data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} + data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} + data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} + data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} + data: {"event": "tts_message", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": "qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"} + data: {"event": "tts_message_end", "conversation_id": "23dd85f3-1a41-4ea0-b7a9-062734ccfaf9", "message_id": "a8bdc41c-13b2-4c18-bfd9-054b9803038c", "created_at": 1721205487, "task_id": "3bf8a0bb-e73b-4690-9e66-4e429bad8ee7", "audio": ""} + ``` + + + + +--- + { key: VersionHistoryContextMenuOptions.edit, name: t('workflow.versionHistory.nameThisVersion'), }, + { + key: VersionHistoryContextMenuOptions.copyId, + name: t('workflow.versionHistory.copyId'), + }, ] - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isNamedVersion]) + }, [isNamedVersion, t]) return { deleteOperation, diff --git a/web/app/components/workflow/panel/version-history-panel/index.tsx b/web/app/components/workflow/panel/version-history-panel/index.tsx index 521ab5878..70acca759 100644 --- a/web/app/components/workflow/panel/version-history-panel/index.tsx +++ b/web/app/components/workflow/panel/version-history-panel/index.tsx @@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import { RiArrowDownDoubleLine, RiCloseLine, RiLoader2Line } from '@remixicon/react' +import copy from 'copy-to-clipboard' import { useNodesSyncDraft, useWorkflowRun } from '../../hooks' import { useStore, useWorkflowStore } from '../../store' import { VersionHistoryContextMenuOptions, WorkflowVersionFilterOptions } from '../../types' @@ -99,8 +100,15 @@ const VersionHistoryPanel = () => { case VersionHistoryContextMenuOptions.delete: setDeleteConfirmOpen(true) break + case VersionHistoryContextMenuOptions.copyId: + copy(item.id) + Toast.notify({ + type: 'success', + message: t('workflow.versionHistory.action.copyIdSuccess'), + }) + break } - }, []) + }, [t]) const handleCancel = useCallback((operation: VersionHistoryContextMenuOptions) => { switch (operation) { diff --git a/web/app/components/workflow/panel/version-history-panel/version-history-item.tsx b/web/app/components/workflow/panel/version-history-panel/version-history-item.tsx index 98fd7ce45..797a3fbe4 100644 --- a/web/app/components/workflow/panel/version-history-panel/version-history-item.tsx +++ b/web/app/components/workflow/panel/version-history-panel/version-history-item.tsx @@ -55,7 +55,6 @@ const VersionHistoryItem: React.FC = ({ useEffect(() => { if (isDraft) onClick(item) - // eslint-disable-next-line react-hooks/exhaustive-deps }, []) const handleClickItem = () => { diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index 11a424c5d..5840a04f2 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -445,6 +445,7 @@ export enum VersionHistoryContextMenuOptions { restore = 'restore', edit = 'edit', delete = 'delete', + copyId = 'copyId', } export type ChildNodeTypeCount = { diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 763739ba3..9a8492f50 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -920,6 +920,7 @@ const translation = { defaultName: 'Untitled Version', nameThisVersion: 'Name this version', editVersionInfo: 'Edit version info', + copyId: 'Copy ID', editField: { title: 'Title', releaseNotes: 'Release Notes', @@ -936,7 +937,8 @@ const translation = { deleteFailure: 'Failed to delete version', updateSuccess: 'Version updated', updateFailure: 'Failed to update version', - }, + copyIdSuccess: 'ID copied to clipboard', + }, }, debug: { settingsTab: 'Settings', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index b1c28c466..25f05ce8b 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -920,6 +920,7 @@ const translation = { defaultName: '未命名', nameThisVersion: '命名', editVersionInfo: '编辑信息', + copyId: '复制 ID', editField: { title: '标题', releaseNotes: '发布说明', @@ -936,6 +937,7 @@ const translation = { deleteFailure: '删除失败', updateSuccess: '版本信息已更新', updateFailure: '更新失败', + copyIdSuccess: 'ID 已复制到剪贴板', }, }, debug: {