您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import {
  2. Position,
  3. } from 'reactflow'
  4. import type {
  5. Node,
  6. } from '../types'
  7. import {
  8. BlockEnum,
  9. } from '../types'
  10. import {
  11. CUSTOM_NODE,
  12. ITERATION_CHILDREN_Z_INDEX,
  13. ITERATION_NODE_Z_INDEX,
  14. LOOP_CHILDREN_Z_INDEX,
  15. LOOP_NODE_Z_INDEX,
  16. } from '../constants'
  17. import { CUSTOM_ITERATION_START_NODE } from '../nodes/iteration-start/constants'
  18. import { CUSTOM_LOOP_START_NODE } from '../nodes/loop-start/constants'
  19. import type { IterationNodeType } from '../nodes/iteration/types'
  20. import type { LoopNodeType } from '../nodes/loop/types'
  21. import { CUSTOM_SIMPLE_NODE } from '@/app/components/workflow/simple-node/constants'
  22. export function generateNewNode({ data, position, id, zIndex, type, ...rest }: Omit<Node, 'id'> & { id?: string }): {
  23. newNode: Node
  24. newIterationStartNode?: Node
  25. newLoopStartNode?: Node
  26. } {
  27. const newNode = {
  28. id: id || `${Date.now()}`,
  29. type: type || CUSTOM_NODE,
  30. data,
  31. position,
  32. targetPosition: Position.Left,
  33. sourcePosition: Position.Right,
  34. zIndex: data.type === BlockEnum.Iteration ? ITERATION_NODE_Z_INDEX : (data.type === BlockEnum.Loop ? LOOP_NODE_Z_INDEX : zIndex),
  35. ...rest,
  36. } as Node
  37. if (data.type === BlockEnum.Iteration) {
  38. const newIterationStartNode = getIterationStartNode(newNode.id);
  39. (newNode.data as IterationNodeType).start_node_id = newIterationStartNode.id;
  40. (newNode.data as IterationNodeType)._children = [{ nodeId: newIterationStartNode.id, nodeType: BlockEnum.IterationStart }]
  41. return {
  42. newNode,
  43. newIterationStartNode,
  44. }
  45. }
  46. if (data.type === BlockEnum.Loop) {
  47. const newLoopStartNode = getLoopStartNode(newNode.id);
  48. (newNode.data as LoopNodeType).start_node_id = newLoopStartNode.id;
  49. (newNode.data as LoopNodeType)._children = [{ nodeId: newLoopStartNode.id, nodeType: BlockEnum.LoopStart }]
  50. return {
  51. newNode,
  52. newLoopStartNode,
  53. }
  54. }
  55. return {
  56. newNode,
  57. }
  58. }
  59. export function getIterationStartNode(iterationId: string): Node {
  60. return generateNewNode({
  61. id: `${iterationId}start`,
  62. type: CUSTOM_ITERATION_START_NODE,
  63. data: {
  64. title: '',
  65. desc: '',
  66. type: BlockEnum.IterationStart,
  67. isInIteration: true,
  68. },
  69. position: {
  70. x: 24,
  71. y: 68,
  72. },
  73. zIndex: ITERATION_CHILDREN_Z_INDEX,
  74. parentId: iterationId,
  75. selectable: false,
  76. draggable: false,
  77. }).newNode
  78. }
  79. export function getLoopStartNode(loopId: string): Node {
  80. return generateNewNode({
  81. id: `${loopId}start`,
  82. type: CUSTOM_LOOP_START_NODE,
  83. data: {
  84. title: '',
  85. desc: '',
  86. type: BlockEnum.LoopStart,
  87. isInLoop: true,
  88. },
  89. position: {
  90. x: 24,
  91. y: 68,
  92. },
  93. zIndex: LOOP_CHILDREN_Z_INDEX,
  94. parentId: loopId,
  95. selectable: false,
  96. draggable: false,
  97. }).newNode
  98. }
  99. export const genNewNodeTitleFromOld = (oldTitle: string) => {
  100. const regex = /^(.+?)\s*\((\d+)\)\s*$/
  101. const match = oldTitle.match(regex)
  102. if (match) {
  103. const title = match[1]
  104. const num = Number.parseInt(match[2], 10)
  105. return `${title} (${num + 1})`
  106. }
  107. else {
  108. return `${oldTitle} (1)`
  109. }
  110. }
  111. export const getTopLeftNodePosition = (nodes: Node[]) => {
  112. let minX = Infinity
  113. let minY = Infinity
  114. nodes.forEach((node) => {
  115. if (node.position.x < minX)
  116. minX = node.position.x
  117. if (node.position.y < minY)
  118. minY = node.position.y
  119. })
  120. return {
  121. x: minX,
  122. y: minY,
  123. }
  124. }
  125. export const getNestedNodePosition = (node: Node, parentNode: Node) => {
  126. return {
  127. x: node.position.x - parentNode.position.x,
  128. y: node.position.y - parentNode.position.y,
  129. }
  130. }
  131. export const hasRetryNode = (nodeType?: BlockEnum) => {
  132. return nodeType === BlockEnum.LLM || nodeType === BlockEnum.Tool || nodeType === BlockEnum.HttpRequest || nodeType === BlockEnum.Code
  133. }
  134. export const getNodeCustomTypeByNodeDataType = (nodeType: BlockEnum) => {
  135. if (nodeType === BlockEnum.LoopEnd)
  136. return CUSTOM_SIMPLE_NODE
  137. }