You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

use-get-begin-query.tsx 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { useFetchAgent } from '@/hooks/use-agent-request';
  2. import { RAGFlowNodeType } from '@/interfaces/database/flow';
  3. import { Edge } from '@xyflow/react';
  4. import { DefaultOptionType } from 'antd/es/select';
  5. import { isEmpty } from 'lodash';
  6. import get from 'lodash/get';
  7. import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
  8. import { BeginId, BeginQueryType, Operator, VariableType } from '../constant';
  9. import { AgentFormContext } from '../context';
  10. import { buildBeginInputListFromObject } from '../form/begin-form/utils';
  11. import { BeginQuery } from '../interface';
  12. import useGraphStore from '../store';
  13. export const useGetBeginNodeDataQuery = () => {
  14. const getNode = useGraphStore((state) => state.getNode);
  15. const getBeginNodeDataQuery = useCallback(() => {
  16. return buildBeginInputListFromObject(
  17. get(getNode(BeginId), 'data.form.inputs', {}),
  18. );
  19. }, [getNode]);
  20. return getBeginNodeDataQuery;
  21. };
  22. export const useGetBeginNodeDataQueryIsSafe = () => {
  23. const [isBeginNodeDataQuerySafe, setIsBeginNodeDataQuerySafe] =
  24. useState(false);
  25. const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
  26. const nodes = useGraphStore((state) => state.nodes);
  27. useEffect(() => {
  28. const query: BeginQuery[] = getBeginNodeDataQuery();
  29. const isSafe = !query.some((q) => !q.optional && q.type === 'file');
  30. setIsBeginNodeDataQuerySafe(isSafe);
  31. }, [getBeginNodeDataQuery, nodes]);
  32. return isBeginNodeDataQuerySafe;
  33. };
  34. function filterAllUpstreamNodeIds(edges: Edge[], nodeIds: string[]) {
  35. return nodeIds.reduce<string[]>((pre, nodeId) => {
  36. const currentEdges = edges.filter((x) => x.target === nodeId);
  37. const upstreamNodeIds: string[] = currentEdges.map((x) => x.source);
  38. const ids = upstreamNodeIds.concat(
  39. filterAllUpstreamNodeIds(edges, upstreamNodeIds),
  40. );
  41. ids.forEach((x) => {
  42. if (pre.every((y) => y !== x)) {
  43. pre.push(x);
  44. }
  45. });
  46. return pre;
  47. }, []);
  48. }
  49. function buildOutputOptions(
  50. outputs: Record<string, any> = {},
  51. nodeId?: string,
  52. ) {
  53. return Object.keys(outputs).map((x) => ({
  54. label: x,
  55. value: `${nodeId}@${x}`,
  56. type: outputs[x]?.type,
  57. }));
  58. }
  59. export function useBuildNodeOutputOptions(nodeId?: string) {
  60. const nodes = useGraphStore((state) => state.nodes);
  61. const edges = useGraphStore((state) => state.edges);
  62. const nodeOutputOptions = useMemo(() => {
  63. if (!nodeId) {
  64. return [];
  65. }
  66. const upstreamIds = filterAllUpstreamNodeIds(edges, [nodeId]);
  67. const nodeWithOutputList = nodes.filter(
  68. (x) =>
  69. upstreamIds.some((y) => y === x.id) && !isEmpty(x.data?.form?.outputs),
  70. );
  71. return nodeWithOutputList
  72. .filter((x) => x.id !== nodeId)
  73. .map((x) => ({
  74. label: x.data.name,
  75. value: x.id,
  76. title: x.data.name,
  77. options: buildOutputOptions(x.data.form.outputs, x.id),
  78. }));
  79. }, [edges, nodeId, nodes]);
  80. return nodeOutputOptions;
  81. }
  82. // exclude nodes with branches
  83. const ExcludedNodes = [
  84. Operator.Categorize,
  85. Operator.Relevant,
  86. Operator.Begin,
  87. Operator.Note,
  88. ];
  89. const StringList = [
  90. BeginQueryType.Line,
  91. BeginQueryType.Paragraph,
  92. BeginQueryType.Options,
  93. ];
  94. function transferToVariableType(type: string) {
  95. if (StringList.some((x) => x === type)) {
  96. return VariableType.String;
  97. }
  98. return type;
  99. }
  100. export function useBuildBeginVariableOptions() {
  101. const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
  102. const options = useMemo(() => {
  103. const query: BeginQuery[] = getBeginNodeDataQuery();
  104. return [
  105. {
  106. label: <span>Begin Input</span>,
  107. title: 'Begin Input',
  108. options: query.map((x) => ({
  109. label: x.name,
  110. value: `begin@${x.key}`,
  111. type: transferToVariableType(x.type),
  112. })),
  113. },
  114. ];
  115. }, [getBeginNodeDataQuery]);
  116. return options;
  117. }
  118. export const useBuildVariableOptions = (nodeId?: string) => {
  119. const nodeOutputOptions = useBuildNodeOutputOptions(nodeId);
  120. const beginOptions = useBuildBeginVariableOptions();
  121. const options = useMemo(() => {
  122. return [...beginOptions, ...nodeOutputOptions];
  123. }, [beginOptions, nodeOutputOptions]);
  124. return options;
  125. };
  126. export function useBuildQueryVariableOptions() {
  127. const { data } = useFetchAgent();
  128. const node = useContext(AgentFormContext);
  129. const options = useBuildVariableOptions(node?.id);
  130. const nextOptions = useMemo(() => {
  131. const globals = data?.dsl?.globals ?? {};
  132. const globalOptions = Object.entries(globals).map(([key, value]) => ({
  133. label: key,
  134. value: key,
  135. type: Array.isArray(value) ? VariableType.Array : typeof value,
  136. }));
  137. return [
  138. { ...options[0], options: [...options[0]?.options, ...globalOptions] },
  139. ...options.slice(1),
  140. ];
  141. }, [data.dsl.globals, options]);
  142. return nextOptions;
  143. }
  144. export function useBuildComponentIdOptions(nodeId?: string, parentId?: string) {
  145. const nodes = useGraphStore((state) => state.nodes);
  146. // Limit the nodes inside iteration to only reference peer nodes with the same parentId and other external nodes other than their parent nodes
  147. const filterChildNodesToSameParentOrExternal = useCallback(
  148. (node: RAGFlowNodeType) => {
  149. // Node inside iteration
  150. if (parentId) {
  151. return (
  152. (node.parentId === parentId || node.parentId === undefined) &&
  153. node.id !== parentId
  154. );
  155. }
  156. return node.parentId === undefined; // The outermost node
  157. },
  158. [parentId],
  159. );
  160. const componentIdOptions = useMemo(() => {
  161. return nodes
  162. .filter(
  163. (x) =>
  164. x.id !== nodeId &&
  165. !ExcludedNodes.some((y) => y === x.data.label) &&
  166. filterChildNodesToSameParentOrExternal(x),
  167. )
  168. .map((x) => ({ label: x.data.name, value: x.id }));
  169. }, [nodes, nodeId, filterChildNodesToSameParentOrExternal]);
  170. return [
  171. {
  172. label: <span>Component Output</span>,
  173. title: 'Component Output',
  174. options: componentIdOptions,
  175. },
  176. ];
  177. }
  178. export function useBuildComponentIdAndBeginOptions(
  179. nodeId?: string,
  180. parentId?: string,
  181. ) {
  182. const componentIdOptions = useBuildComponentIdOptions(nodeId, parentId);
  183. const beginOptions = useBuildBeginVariableOptions();
  184. return [...beginOptions, ...componentIdOptions];
  185. }
  186. export const useGetComponentLabelByValue = (nodeId: string) => {
  187. const options = useBuildComponentIdAndBeginOptions(nodeId);
  188. const flattenOptions = useMemo(() => {
  189. return options.reduce<DefaultOptionType[]>((pre, cur) => {
  190. return [...pre, ...cur.options];
  191. }, []);
  192. }, [options]);
  193. const getLabel = useCallback(
  194. (val?: string) => {
  195. return flattenOptions.find((x) => x.value === val)?.label;
  196. },
  197. [flattenOptions],
  198. );
  199. return getLabel;
  200. };