2024-05-27 08:21:30 +08:00
|
|
|
import { DSLComponents } from '@/interfaces/database/flow';
|
2024-06-06 11:01:14 +08:00
|
|
|
import { removeUselessFieldsFromValues } from '@/utils/form';
|
2024-07-01 17:12:04 +08:00
|
|
|
import { humanId } from 'human-id';
|
2024-07-11 18:01:50 +08:00
|
|
|
import { curry, sample } from 'lodash';
|
2024-06-06 15:00:37 +08:00
|
|
|
import pipe from 'lodash/fp/pipe';
|
2024-07-09 16:34:59 +08:00
|
|
|
import isObject from 'lodash/isObject';
|
2024-07-02 11:43:57 +08:00
|
|
|
import { Edge, Node, Position } from 'reactflow';
|
2024-05-27 08:21:30 +08:00
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
2024-07-11 18:01:50 +08:00
|
|
|
import { CategorizeAnchorPointPositions, NodeMap, Operator } from './constant';
|
|
|
|
|
import { ICategorizeItemResult, IPosition, NodeData } from './interface';
|
2024-05-27 08:21:30 +08:00
|
|
|
|
2024-05-27 19:35:14 +08:00
|
|
|
const buildEdges = (
|
|
|
|
|
operatorIds: string[],
|
|
|
|
|
currentId: string,
|
|
|
|
|
allEdges: Edge[],
|
|
|
|
|
isUpstream = false,
|
2024-07-01 14:37:05 +08:00
|
|
|
componentName: string,
|
|
|
|
|
nodeParams: Record<string, unknown>,
|
2024-05-27 19:35:14 +08:00
|
|
|
) => {
|
|
|
|
|
operatorIds.forEach((cur) => {
|
|
|
|
|
const source = isUpstream ? cur : currentId;
|
|
|
|
|
const target = isUpstream ? currentId : cur;
|
|
|
|
|
if (!allEdges.some((e) => e.source === source && e.target === target)) {
|
2024-07-01 14:37:05 +08:00
|
|
|
const edge: Edge = {
|
2024-05-27 19:35:14 +08:00
|
|
|
id: uuidv4(),
|
|
|
|
|
label: '',
|
2024-05-29 10:01:39 +08:00
|
|
|
// type: 'step',
|
2024-05-27 19:35:14 +08:00
|
|
|
source: source,
|
|
|
|
|
target: target,
|
2024-07-02 11:43:57 +08:00
|
|
|
// markerEnd: {
|
|
|
|
|
// type: MarkerType.ArrowClosed,
|
|
|
|
|
// color: 'rgb(157 149 225)',
|
|
|
|
|
// width: 20,
|
|
|
|
|
// height: 20,
|
|
|
|
|
// },
|
2024-07-01 14:37:05 +08:00
|
|
|
};
|
|
|
|
|
if (componentName === Operator.Categorize && !isUpstream) {
|
|
|
|
|
const categoryDescription =
|
|
|
|
|
nodeParams.category_description as ICategorizeItemResult;
|
|
|
|
|
|
|
|
|
|
const name = Object.keys(categoryDescription).find(
|
|
|
|
|
(x) => categoryDescription[x].to === target,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (name) {
|
|
|
|
|
edge.sourceHandle = name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
allEdges.push(edge);
|
2024-05-27 19:35:14 +08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const buildNodesAndEdgesFromDSLComponents = (data: DSLComponents) => {
|
2024-05-27 08:21:30 +08:00
|
|
|
const nodes: Node[] = [];
|
2024-05-27 19:35:14 +08:00
|
|
|
let edges: Edge[] = [];
|
2024-05-27 08:21:30 +08:00
|
|
|
|
|
|
|
|
Object.entries(data).forEach(([key, value]) => {
|
|
|
|
|
const downstream = [...value.downstream];
|
|
|
|
|
const upstream = [...value.upstream];
|
2024-07-01 14:37:05 +08:00
|
|
|
const { component_name: componentName, params } = value.obj;
|
2024-05-27 08:21:30 +08:00
|
|
|
nodes.push({
|
|
|
|
|
id: key,
|
2024-07-01 10:27:32 +08:00
|
|
|
type: NodeMap[value.obj.component_name as Operator] || 'ragNode',
|
2024-05-27 08:21:30 +08:00
|
|
|
position: { x: 0, y: 0 },
|
|
|
|
|
data: {
|
2024-07-01 14:37:05 +08:00
|
|
|
label: componentName,
|
2024-07-01 17:12:04 +08:00
|
|
|
name: humanId(),
|
2024-07-01 14:37:05 +08:00
|
|
|
form: params,
|
2024-05-27 08:21:30 +08:00
|
|
|
},
|
|
|
|
|
sourcePosition: Position.Left,
|
|
|
|
|
targetPosition: Position.Right,
|
|
|
|
|
});
|
|
|
|
|
|
2024-07-01 14:37:05 +08:00
|
|
|
buildEdges(upstream, key, edges, true, componentName, params);
|
|
|
|
|
buildEdges(downstream, key, edges, false, componentName, params);
|
2024-05-27 19:35:14 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return { nodes, edges };
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-05 10:46:06 +08:00
|
|
|
const buildComponentDownstreamOrUpstream = (
|
|
|
|
|
edges: Edge[],
|
|
|
|
|
nodeId: string,
|
|
|
|
|
isBuildDownstream = true,
|
|
|
|
|
) => {
|
|
|
|
|
return edges
|
|
|
|
|
.filter((y) => y[isBuildDownstream ? 'source' : 'target'] === nodeId)
|
|
|
|
|
.map((y) => y[isBuildDownstream ? 'target' : 'source']);
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-06 15:00:37 +08:00
|
|
|
const removeUselessDataInTheOperator = curry(
|
|
|
|
|
(operatorName: string, params: Record<string, unknown>) => {
|
2024-06-25 19:28:24 +08:00
|
|
|
if (
|
|
|
|
|
operatorName === Operator.Generate ||
|
|
|
|
|
operatorName === Operator.Categorize
|
|
|
|
|
) {
|
2024-06-06 15:00:37 +08:00
|
|
|
return removeUselessFieldsFromValues(params, '');
|
|
|
|
|
}
|
|
|
|
|
return params;
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
// initialize data for operators without parameters
|
2024-07-04 19:18:02 +08:00
|
|
|
// const initializeOperatorParams = curry((operatorName: string, values: any) => {
|
|
|
|
|
// if (isEmpty(values)) {
|
|
|
|
|
// return initialFormValuesMap[operatorName as Operator];
|
|
|
|
|
// }
|
|
|
|
|
// return values;
|
|
|
|
|
// });
|
2024-06-06 15:00:37 +08:00
|
|
|
|
|
|
|
|
const buildOperatorParams = (operatorName: string) =>
|
|
|
|
|
pipe(
|
|
|
|
|
removeUselessDataInTheOperator(operatorName),
|
2024-07-04 19:18:02 +08:00
|
|
|
// initializeOperatorParams(operatorName), // Final processing, for guarantee
|
2024-06-06 15:00:37 +08:00
|
|
|
);
|
2024-06-06 11:01:14 +08:00
|
|
|
|
2024-06-05 10:46:06 +08:00
|
|
|
// construct a dsl based on the node information of the graph
|
|
|
|
|
export const buildDslComponentsByGraph = (
|
|
|
|
|
nodes: Node<NodeData>[],
|
|
|
|
|
edges: Edge[],
|
|
|
|
|
): DSLComponents => {
|
|
|
|
|
const components: DSLComponents = {};
|
|
|
|
|
|
|
|
|
|
nodes.forEach((x) => {
|
|
|
|
|
const id = x.id;
|
2024-06-06 11:01:14 +08:00
|
|
|
const operatorName = x.data.label;
|
2024-06-05 10:46:06 +08:00
|
|
|
components[id] = {
|
|
|
|
|
obj: {
|
2024-06-06 11:01:14 +08:00
|
|
|
component_name: operatorName,
|
|
|
|
|
params:
|
2024-06-06 15:00:37 +08:00
|
|
|
buildOperatorParams(operatorName)(
|
2024-06-06 11:01:14 +08:00
|
|
|
x.data.form as Record<string, unknown>,
|
|
|
|
|
) ?? {},
|
2024-06-05 10:46:06 +08:00
|
|
|
},
|
|
|
|
|
downstream: buildComponentDownstreamOrUpstream(edges, id, true),
|
|
|
|
|
upstream: buildComponentDownstreamOrUpstream(edges, id, false),
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return components;
|
|
|
|
|
};
|
2024-07-05 14:16:03 +08:00
|
|
|
|
|
|
|
|
export const receiveMessageError = (res: any) =>
|
|
|
|
|
res && (res?.response.status !== 200 || res?.data?.retcode !== 0);
|
2024-07-09 16:34:59 +08:00
|
|
|
|
|
|
|
|
// Replace the id in the object with text
|
|
|
|
|
export const replaceIdWithText = (
|
|
|
|
|
obj: Record<string, unknown> | unknown[] | unknown,
|
|
|
|
|
getNameById: (id?: string) => string | undefined,
|
|
|
|
|
) => {
|
|
|
|
|
if (isObject(obj)) {
|
|
|
|
|
const ret: Record<string, unknown> | unknown[] = Array.isArray(obj)
|
|
|
|
|
? []
|
|
|
|
|
: {};
|
|
|
|
|
Object.keys(obj).forEach((key) => {
|
|
|
|
|
const val = (obj as Record<string, unknown>)[key];
|
|
|
|
|
const text = typeof val === 'string' ? getNameById(val) : undefined;
|
|
|
|
|
(ret as Record<string, unknown>)[key] = text
|
|
|
|
|
? text
|
|
|
|
|
: replaceIdWithText(val, getNameById);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
};
|
2024-07-11 18:01:50 +08:00
|
|
|
|
|
|
|
|
export const isEdgeEqual = (previous: Edge, current: Edge) =>
|
|
|
|
|
previous.source === current.source &&
|
|
|
|
|
previous.target === current.target &&
|
|
|
|
|
previous.sourceHandle === current.sourceHandle;
|
|
|
|
|
|
|
|
|
|
export const buildNewPositionMap = (
|
|
|
|
|
categoryDataKeys: string[],
|
|
|
|
|
indexesInUse: number[],
|
|
|
|
|
) => {
|
|
|
|
|
return categoryDataKeys.reduce<Record<string, IPosition>>((pre, cur) => {
|
|
|
|
|
// take a coordinate
|
|
|
|
|
const effectiveIdxes = CategorizeAnchorPointPositions.map(
|
|
|
|
|
(x, idx) => idx,
|
|
|
|
|
).filter((x) => !indexesInUse.some((y) => y === x));
|
|
|
|
|
const idx = sample(effectiveIdxes);
|
|
|
|
|
if (idx !== undefined) {
|
|
|
|
|
indexesInUse.push(idx);
|
|
|
|
|
pre[cur] = { ...CategorizeAnchorPointPositions[idx], idx };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pre;
|
|
|
|
|
}, {});
|
|
|
|
|
};
|