123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- import { useCallback } from 'react'
- import {
- useReactFlow,
- useStoreApi,
- } from 'reactflow'
- import produce from 'immer'
- import { useWorkflowStore } from '../store'
- import {
- NodeRunningStatus,
- WorkflowRunningStatus,
- } from '../types'
- import { useWorkflow } from './use-workflow'
- import { useStore as useAppStore } from '@/app/components/app/store'
- import type { IOtherOptions } from '@/service/base'
- import { ssePost } from '@/service/base'
- import {
- fetchPublishedWorkflow,
- stopWorkflowRun,
- } from '@/service/workflow'
- import { useFeaturesStore } from '@/app/components/base/features/hooks'
- export const useWorkflowRun = () => {
- const store = useStoreApi()
- const workflowStore = useWorkflowStore()
- const reactflow = useReactFlow()
- const featuresStore = useFeaturesStore()
- const { renderTreeFromRecord } = useWorkflow()
- const handleBackupDraft = useCallback(() => {
- const {
- getNodes,
- edges,
- } = store.getState()
- const { getViewport } = reactflow
- const {
- backupDraft,
- setBackupDraft,
- } = workflowStore.getState()
- const { features } = featuresStore!.getState()
- if (!backupDraft) {
- setBackupDraft({
- nodes: getNodes(),
- edges,
- viewport: getViewport(),
- features,
- })
- }
- }, [reactflow, workflowStore, store, featuresStore])
- const handleLoadBackupDraft = useCallback(() => {
- const {
- setNodes,
- setEdges,
- } = store.getState()
- const { setViewport } = reactflow
- const {
- backupDraft,
- setBackupDraft,
- } = workflowStore.getState()
- if (backupDraft) {
- const {
- nodes,
- edges,
- viewport,
- features,
- } = backupDraft
- setNodes(nodes)
- setEdges(edges)
- setViewport(viewport)
- featuresStore!.setState({ features })
- setBackupDraft(undefined)
- }
- }, [store, reactflow, workflowStore, featuresStore])
- const handleRunSetting = useCallback((shouldClear?: boolean) => {
- if (shouldClear) {
- workflowStore.setState({
- workflowRunningData: undefined,
- historyWorkflowData: undefined,
- showInputsPanel: false,
- })
- }
- else {
- workflowStore.setState({
- workflowRunningData: {
- result: {
- status: shouldClear ? '' : WorkflowRunningStatus.Waiting,
- },
- tracing: [],
- },
- })
- }
- const {
- setNodes,
- getNodes,
- edges,
- setEdges,
- } = store.getState()
- if (shouldClear) {
- handleLoadBackupDraft()
- }
- else {
- handleBackupDraft()
- const newNodes = produce(getNodes(), (draft) => {
- draft.forEach((node) => {
- node.data._runningStatus = NodeRunningStatus.Waiting
- })
- })
- setNodes(newNodes)
- const newEdges = produce(edges, (draft) => {
- draft.forEach((edge) => {
- edge.data._runned = false
- })
- })
- setEdges(newEdges)
- }
- }, [store, handleLoadBackupDraft, handleBackupDraft, workflowStore])
- const handleRun = useCallback((
- params: any,
- callback?: IOtherOptions,
- ) => {
- const {
- onWorkflowStarted,
- onWorkflowFinished,
- onNodeStarted,
- onNodeFinished,
- onError,
- ...restCallback
- } = callback || {}
- workflowStore.setState({ historyWorkflowData: undefined })
- const appDetail = useAppStore.getState().appDetail
- const workflowContainer = document.getElementById('workflow-container')
- const {
- clientWidth,
- clientHeight,
- } = workflowContainer!
- let url = ''
- if (appDetail?.mode === 'advanced-chat')
- url = `/apps/${appDetail.id}/advanced-chat/workflows/draft/run`
- if (appDetail?.mode === 'workflow')
- url = `/apps/${appDetail.id}/workflows/draft/run`
- let prevNodeId = ''
- const {
- workflowRunningData,
- setWorkflowRunningData,
- } = workflowStore.getState()
- setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
- draft.result = {
- ...draft?.result,
- status: WorkflowRunningStatus.Running,
- }
- }))
- ssePost(
- url,
- {
- body: params,
- },
- {
- onWorkflowStarted: (params) => {
- const { task_id, data } = params
- const {
- workflowRunningData,
- setWorkflowRunningData,
- } = workflowStore.getState()
- const {
- getNodes,
- setNodes,
- edges,
- setEdges,
- } = store.getState()
- setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
- draft.task_id = task_id
- draft.result = {
- ...draft?.result,
- ...data,
- status: WorkflowRunningStatus.Running,
- }
- }))
- const newNodes = produce(getNodes(), (draft) => {
- draft.forEach((node) => {
- node.data._runningStatus = NodeRunningStatus.Waiting
- })
- })
- setNodes(newNodes)
- const newEdges = produce(edges, (draft) => {
- draft.forEach((edge) => {
- edge.data = {
- ...edge.data,
- _runned: false,
- }
- })
- })
- setEdges(newEdges)
- if (onWorkflowStarted)
- onWorkflowStarted(params)
- },
- onWorkflowFinished: (params) => {
- const { data } = params
- const {
- workflowRunningData,
- setWorkflowRunningData,
- } = workflowStore.getState()
- setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
- draft.result = {
- ...draft.result,
- ...data,
- }
- }))
- prevNodeId = ''
- if (onWorkflowFinished)
- onWorkflowFinished(params)
- },
- onError: (params) => {
- const {
- workflowRunningData,
- setWorkflowRunningData,
- } = workflowStore.getState()
- setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
- draft.result = {
- ...draft.result,
- status: WorkflowRunningStatus.Failed,
- }
- }))
- if (onError)
- onError(params)
- },
- onNodeStarted: (params) => {
- const { data } = params
- const {
- workflowRunningData,
- setWorkflowRunningData,
- } = workflowStore.getState()
- const {
- getNodes,
- setNodes,
- edges,
- setEdges,
- } = store.getState()
- const nodes = getNodes()
- setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
- draft.tracing!.push({
- ...data,
- status: NodeRunningStatus.Running,
- } as any)
- }))
- const {
- setViewport,
- } = reactflow
- const currentNodeIndex = nodes.findIndex(node => node.id === data.node_id)
- const currentNode = nodes[currentNodeIndex]
- const position = currentNode.position
- const zoom = 1
- setViewport({
- x: (clientWidth - 400 - currentNode.width!) / 2 - position.x,
- y: (clientHeight - currentNode.height!) / 2 - position.y,
- zoom,
- })
- const newNodes = produce(nodes, (draft) => {
- draft[currentNodeIndex].data._runningStatus = NodeRunningStatus.Running
- })
- setNodes(newNodes)
- const newEdges = produce(edges, (draft) => {
- const edge = draft.find(edge => edge.target === data.node_id && edge.source === prevNodeId)
- if (edge)
- edge.data = { ...edge.data, _runned: true } as any
- })
- setEdges(newEdges)
- if (onNodeStarted)
- onNodeStarted(params)
- },
- onNodeFinished: (params) => {
- const { data } = params
- const {
- workflowRunningData,
- setWorkflowRunningData,
- } = workflowStore.getState()
- const {
- getNodes,
- setNodes,
- } = store.getState()
- const nodes = getNodes()
- setWorkflowRunningData(produce(workflowRunningData!, (draft) => {
- const currentIndex = draft.tracing!.findIndex(trace => trace.node_id === data.node_id)
- if (currentIndex > -1 && draft.tracing) {
- draft.tracing[currentIndex] = {
- ...(draft.tracing[currentIndex].extras
- ? { extras: draft.tracing[currentIndex].extras }
- : {}),
- ...data,
- } as any
- }
- }))
- const newNodes = produce(nodes, (draft) => {
- const currentNode = draft.find(node => node.id === data.node_id)!
- currentNode.data._runningStatus = data.status as any
- })
- setNodes(newNodes)
- prevNodeId = data.node_id
- if (onNodeFinished)
- onNodeFinished(params)
- },
- ...restCallback,
- },
- )
- }, [store, reactflow, workflowStore])
- const handleStopRun = useCallback((taskId: string) => {
- const appId = useAppStore.getState().appDetail?.id
- stopWorkflowRun(`/apps/${appId}/workflow-runs/tasks/${taskId}/stop`)
- }, [])
- const handleRestoreFromPublishedWorkflow = useCallback(async () => {
- const appDetail = useAppStore.getState().appDetail
- const publishedWorkflow = await fetchPublishedWorkflow(`/apps/${appDetail?.id}/workflows/publish`)
- if (publishedWorkflow) {
- const nodes = publishedWorkflow.graph.nodes
- const edges = publishedWorkflow.graph.edges
- const viewport = publishedWorkflow.graph.viewport
- renderTreeFromRecord(nodes, edges, viewport)
- featuresStore?.setState({ features: publishedWorkflow.features })
- workflowStore.getState().setPublishedAt(publishedWorkflow.created_at)
- }
- }, [featuresStore, workflowStore, renderTreeFromRecord])
- return {
- handleBackupDraft,
- handleLoadBackupDraft,
- handleRunSetting,
- handleRun,
- handleStopRun,
- handleRestoreFromPublishedWorkflow,
- }
- }
|