Merge branch 'develop-mark' into develop
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""
|
||||
工作流服务层
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
import datetime
|
||||
@@ -438,7 +438,7 @@ class WorkflowService:
|
||||
message=f"工作流配置不存在: app_id={app_id}"
|
||||
)
|
||||
input_data = {"message": payload.message, "variables": payload.variables, "conversation_id": payload.conversation_id}
|
||||
|
||||
|
||||
# 转换 user_id 为 UUID
|
||||
triggered_by_uuid = None
|
||||
if payload.user_id:
|
||||
@@ -446,7 +446,7 @@ class WorkflowService:
|
||||
triggered_by_uuid = uuid.UUID(payload.user_id)
|
||||
except (ValueError, AttributeError):
|
||||
logger.warning(f"无效的 user_id 格式: {payload.user_id}")
|
||||
|
||||
|
||||
# 转换 conversation_id 为 UUID
|
||||
conversation_id_uuid = None
|
||||
if payload.conversation_id:
|
||||
@@ -454,7 +454,7 @@ class WorkflowService:
|
||||
conversation_id_uuid = uuid.UUID(payload.conversation_id)
|
||||
except (ValueError, AttributeError):
|
||||
logger.warning(f"无效的 conversation_id 格式: {payload.conversation_id}")
|
||||
|
||||
|
||||
# 2. 创建执行记录
|
||||
execution = self.create_execution(
|
||||
workflow_config_id=config.id,
|
||||
@@ -530,6 +530,109 @@ class WorkflowService:
|
||||
message=f"工作流执行失败: {str(e)}"
|
||||
)
|
||||
|
||||
async def run_stream(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
payload: DraftRunRequest,
|
||||
config: WorkflowConfig
|
||||
):
|
||||
"""运行工作流(流式)
|
||||
|
||||
Args:
|
||||
app_id: 应用 ID
|
||||
payload: 请求对象(包含 message, variables, conversation_id 等)
|
||||
config: 存储类型(可选)
|
||||
|
||||
Yields:
|
||||
SSE 格式的流式事件
|
||||
|
||||
Raises:
|
||||
BusinessException: 配置不存在或执行失败时抛出
|
||||
"""
|
||||
# 1. 获取工作流配置
|
||||
if not config:
|
||||
config = self.get_workflow_config(app_id)
|
||||
if not config:
|
||||
raise BusinessException(
|
||||
code=BizCode.CONFIG_MISSING,
|
||||
message=f"工作流配置不存在: app_id={app_id}"
|
||||
)
|
||||
input_data = {"message": payload.message, "variables": payload.variables,
|
||||
"conversation_id": payload.conversation_id}
|
||||
|
||||
# 转换 user_id 为 UUID
|
||||
triggered_by_uuid = None
|
||||
if payload.user_id:
|
||||
try:
|
||||
triggered_by_uuid = uuid.UUID(payload.user_id)
|
||||
except (ValueError, AttributeError):
|
||||
logger.warning(f"无效的 user_id 格式: {payload.user_id}")
|
||||
|
||||
# 转换 conversation_id 为 UUID
|
||||
conversation_id_uuid = None
|
||||
if payload.conversation_id:
|
||||
try:
|
||||
conversation_id_uuid = uuid.UUID(payload.conversation_id)
|
||||
except (ValueError, AttributeError):
|
||||
logger.warning(f"无效的 conversation_id 格式: {payload.conversation_id}")
|
||||
|
||||
# 2. 创建执行记录
|
||||
execution = self.create_execution(
|
||||
workflow_config_id=config.id,
|
||||
app_id=app_id,
|
||||
trigger_type="manual",
|
||||
triggered_by=triggered_by_uuid,
|
||||
conversation_id=conversation_id_uuid,
|
||||
input_data=input_data
|
||||
)
|
||||
|
||||
# 3. 构建工作流配置字典
|
||||
workflow_config_dict = {
|
||||
"nodes": config.nodes,
|
||||
"edges": config.edges,
|
||||
"variables": config.variables,
|
||||
"execution_config": config.execution_config
|
||||
}
|
||||
|
||||
# 4. 获取工作空间 ID(从 app 获取)
|
||||
from app.models import App
|
||||
|
||||
# 5. 流式执行工作流
|
||||
from app.core.workflow.executor import execute_workflow, execute_workflow_stream
|
||||
|
||||
try:
|
||||
# 更新状态为运行中
|
||||
self.update_execution_status(execution.execution_id, "running")
|
||||
|
||||
# 发送开始事件
|
||||
yield f"data: {json.dumps({'type': 'workflow_start', 'execution_id': execution.execution_id})}\n\n"
|
||||
|
||||
# 调用流式执行
|
||||
async for event in self._run_workflow_stream(
|
||||
workflow_config=workflow_config_dict,
|
||||
input_data=input_data,
|
||||
execution_id=execution.execution_id,
|
||||
workspace_id="",
|
||||
user_id=payload.user_id
|
||||
):
|
||||
# 清理事件数据,移除不可序列化的对象
|
||||
cleaned_event = self._clean_event_for_json(event)
|
||||
# 转换为 SSE 格式
|
||||
yield f"data: {json.dumps(cleaned_event)}\n\n"
|
||||
|
||||
# 发送完成事件
|
||||
yield f"data: {json.dumps({'type': 'workflow_end', 'execution_id': execution.execution_id})}\n\n"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"工作流流式执行失败: execution_id={execution.execution_id}, error={e}", exc_info=True)
|
||||
self.update_execution_status(
|
||||
execution.execution_id,
|
||||
"failed",
|
||||
error_message=str(e)
|
||||
)
|
||||
# 发送错误事件
|
||||
yield f"data: {json.dumps({'type': 'error', 'execution_id': execution.execution_id, 'error': str(e)})}\n\n"
|
||||
|
||||
async def run_workflow(
|
||||
self,
|
||||
app_id: uuid.UUID,
|
||||
@@ -651,14 +754,44 @@ class WorkflowService:
|
||||
message=f"工作流执行失败: {str(e)}"
|
||||
)
|
||||
|
||||
def _clean_event_for_json(self, event: dict[str, Any]) -> dict[str, Any]:
|
||||
"""清理事件数据,移除不可序列化的对象
|
||||
|
||||
Args:
|
||||
event: 原始事件数据
|
||||
|
||||
Returns:
|
||||
可序列化的事件数据
|
||||
"""
|
||||
from langchain_core.messages import BaseMessage
|
||||
|
||||
def clean_value(value):
|
||||
"""递归清理值"""
|
||||
if isinstance(value, BaseMessage):
|
||||
# 将 Message 对象转换为字典
|
||||
return {
|
||||
"type": value.__class__.__name__,
|
||||
"content": value.content,
|
||||
}
|
||||
elif isinstance(value, dict):
|
||||
return {k: clean_value(v) for k, v in value.items()}
|
||||
elif isinstance(value, list):
|
||||
return [clean_value(item) for item in value]
|
||||
elif isinstance(value, (str, int, float, bool, type(None))):
|
||||
return value
|
||||
else:
|
||||
# 其他不可序列化的对象转换为字符串
|
||||
return str(value)
|
||||
|
||||
return clean_value(event)
|
||||
|
||||
async def _run_workflow_stream(
|
||||
self,
|
||||
workflow_config: dict[str, Any],
|
||||
input_data: dict[str, Any],
|
||||
execution_id: str,
|
||||
workspace_id: str,
|
||||
user_id: str
|
||||
):
|
||||
user_id: str):
|
||||
"""运行工作流(流式,内部方法)
|
||||
|
||||
Args:
|
||||
|
||||
Reference in New Issue
Block a user