mirror of
https://github.com/labring/FastGPT.git
synced 2025-10-14 23:22:22 +00:00
perf: vector format (#5516)
* perf: vector format * feat: embedding batch size
This commit is contained in:
@@ -10,12 +10,14 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
|
||||
import { ModelProviderList } from '@fastgpt/global/core/ai/provider';
|
||||
import MultipleRowSelect from '@fastgpt/web/components/common/MySelect/MultipleRowSelect';
|
||||
import { getModelFromList } from '@fastgpt/global/core/ai/model';
|
||||
import type { ResponsiveValue } from '@chakra-ui/system';
|
||||
|
||||
type Props = SelectProps & {
|
||||
disableTip?: string;
|
||||
noOfLines?: ResponsiveValue<number>;
|
||||
};
|
||||
|
||||
const OneRowSelector = ({ list, onChange, disableTip, ...props }: Props) => {
|
||||
const OneRowSelector = ({ list, onChange, disableTip, noOfLines, ...props }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { llmModelList, embeddingModelList, ttsModelList, sttModelList, reRankModelList } =
|
||||
useSystemStore();
|
||||
@@ -55,7 +57,7 @@ const OneRowSelector = ({ list, onChange, disableTip, ...props }: Props) => {
|
||||
fallbackSrc={HUGGING_FACE_ICON}
|
||||
/>
|
||||
|
||||
<Box noOfLines={1}>{modelData.name}</Box>
|
||||
<Box noOfLines={noOfLines}>{modelData.name}</Box>
|
||||
</Flex>
|
||||
)
|
||||
};
|
||||
@@ -99,7 +101,14 @@ const OneRowSelector = ({ list, onChange, disableTip, ...props }: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const MultipleRowSelector = ({ list, onChange, disableTip, placeholder, ...props }: Props) => {
|
||||
const MultipleRowSelector = ({
|
||||
list,
|
||||
onChange,
|
||||
disableTip,
|
||||
placeholder,
|
||||
noOfLines,
|
||||
...props
|
||||
}: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { llmModelList, embeddingModelList, ttsModelList, sttModelList, reRankModelList } =
|
||||
useSystemStore();
|
||||
@@ -189,7 +198,7 @@ const MultipleRowSelector = ({ list, onChange, disableTip, placeholder, ...props
|
||||
fallbackSrc={HUGGING_FACE_ICON}
|
||||
w={avatarSize}
|
||||
/>
|
||||
<Box noOfLines={1}>{modelData?.name}</Box>
|
||||
<Box noOfLines={noOfLines}>{modelData?.name}</Box>
|
||||
</Flex>
|
||||
);
|
||||
}, [modelList, props.value, t, avatarSize]);
|
||||
@@ -222,7 +231,7 @@ const MultipleRowSelector = ({ list, onChange, disableTip, placeholder, ...props
|
||||
};
|
||||
|
||||
const AIModelSelector = (props: Props) => {
|
||||
return props.list.length > 100 ? (
|
||||
return props.list.length > 10 ? (
|
||||
<MultipleRowSelector {...props} />
|
||||
) : (
|
||||
<OneRowSelector {...props} />
|
||||
|
@@ -476,6 +476,26 @@ export const ModelEditModal = ({
|
||||
</Flex>
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>
|
||||
<HStack spacing={1}>
|
||||
<Box>{t('account_model:batch_size')}</Box>
|
||||
</HStack>
|
||||
</Td>
|
||||
<Td textAlign={'right'}>
|
||||
<Flex justifyContent={'flex-end'}>
|
||||
<MyNumberInput
|
||||
defaultValue={1}
|
||||
register={register}
|
||||
name="batchSize"
|
||||
min={1}
|
||||
step={1}
|
||||
isRequired
|
||||
{...InputStyles}
|
||||
/>
|
||||
</Flex>
|
||||
</Td>
|
||||
</Tr>
|
||||
<Tr>
|
||||
<Td>
|
||||
<HStack spacing={1}>
|
||||
|
@@ -48,6 +48,7 @@ export const useDebug = () => {
|
||||
const getNodes = useContextSelector(WorkflowNodeEdgeContext, (v) => v.getNodes);
|
||||
const edges = useContextSelector(WorkflowNodeEdgeContext, (v) => v.edges);
|
||||
const onUpdateNodeError = useContextSelector(WorkflowContext, (v) => v.onUpdateNodeError);
|
||||
const onRemoveError = useContextSelector(WorkflowContext, (v) => v.onRemoveError);
|
||||
const onStartNodeDebug = useContextSelector(WorkflowContext, (v) => v.onStartNodeDebug);
|
||||
|
||||
const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
|
||||
@@ -80,6 +81,7 @@ export const useDebug = () => {
|
||||
|
||||
const checkResults = checkWorkflowNodeAndConnection({ nodes, edges });
|
||||
if (!checkResults) {
|
||||
onRemoveError();
|
||||
const storeNodes = uiWorkflow2StoreWorkflow({ nodes, edges });
|
||||
|
||||
return JSON.stringify(storeNodes);
|
||||
|
@@ -157,6 +157,7 @@ type WorkflowContextType = {
|
||||
nodeList: FlowNodeItemType[];
|
||||
|
||||
onUpdateNodeError: (node: string, isError: Boolean) => void;
|
||||
onRemoveError: () => void;
|
||||
onResetNode: (e: { id: string; node: FlowNodeTemplateType }) => void;
|
||||
onChangeNode: (e: FlowNodeChangeProps) => void;
|
||||
getNodeDynamicInputs: (nodeId: string) => FlowNodeInputItemType[];
|
||||
@@ -401,6 +402,9 @@ export const WorkflowContext = createContext<WorkflowContextType>({
|
||||
isSaved?: boolean;
|
||||
}): boolean {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
onRemoveError: function (): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -473,6 +477,17 @@ const WorkflowContextProvider = ({
|
||||
});
|
||||
});
|
||||
});
|
||||
const onRemoveError = useMemoizedFn(() => {
|
||||
setNodes((state) => {
|
||||
return state.map((item) => {
|
||||
if (item.data.isError) {
|
||||
item.data.isError = false;
|
||||
item.selected = false;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// reset a node data. delete edge and replace it
|
||||
const onResetNode = useMemoizedFn(({ id, node }: { id: string; node: FlowNodeTemplateType }) => {
|
||||
@@ -625,6 +640,7 @@ const WorkflowContextProvider = ({
|
||||
const checkResults = checkWorkflowNodeAndConnection({ nodes, edges });
|
||||
|
||||
if (!checkResults) {
|
||||
onRemoveError();
|
||||
const storeWorkflow = uiWorkflow2StoreWorkflow({ nodes, edges });
|
||||
|
||||
return storeWorkflow;
|
||||
@@ -1025,6 +1041,7 @@ const WorkflowContextProvider = ({
|
||||
// node
|
||||
nodeList,
|
||||
onUpdateNodeError,
|
||||
onRemoveError,
|
||||
onResetNode,
|
||||
onChangeNode,
|
||||
getNodeDynamicInputs,
|
||||
@@ -1075,6 +1092,7 @@ const WorkflowContextProvider = ({
|
||||
onChangeNode,
|
||||
onDelEdge,
|
||||
onNextNodeDebug,
|
||||
onRemoveError,
|
||||
onResetNode,
|
||||
onStartNodeDebug,
|
||||
onStopNodeDebug,
|
||||
|
@@ -248,6 +248,7 @@ const HomeChatWindow = ({ myApps }: Props) => {
|
||||
size="sm"
|
||||
bg={'myGray.50'}
|
||||
rounded="full"
|
||||
noOfLines={[1, 3]}
|
||||
list={availableModels}
|
||||
value={selectedModel}
|
||||
onChange={async (model) => {
|
||||
|
@@ -381,6 +381,11 @@ export const getNodeAllSource = ({
|
||||
};
|
||||
|
||||
/* ====== Connection ======= */
|
||||
// Connectivity check result type
|
||||
type ConnectivityIssue = {
|
||||
nodeId: string;
|
||||
issue: 'isolated' | 'no_input' | 'unreachable_from_start';
|
||||
};
|
||||
export const checkWorkflowNodeAndConnection = ({
|
||||
nodes,
|
||||
edges
|
||||
@@ -388,7 +393,7 @@ export const checkWorkflowNodeAndConnection = ({
|
||||
nodes: Node<FlowNodeItemType, string | undefined>[];
|
||||
edges: Edge<any>[];
|
||||
}): string[] | undefined => {
|
||||
// 1. reference check. Required value
|
||||
// Node check
|
||||
for (const node of nodes) {
|
||||
const data = node.data;
|
||||
const inputs = data.inputs;
|
||||
@@ -453,6 +458,15 @@ export const checkWorkflowNodeAndConnection = ({
|
||||
return [data.nodeId];
|
||||
}
|
||||
}
|
||||
if (data.flowNodeType === FlowNodeTypeEnum.agent) {
|
||||
const toolConnections = edges.filter(
|
||||
(edge) =>
|
||||
edge.source === data.nodeId && edge.sourceHandle === NodeOutputKeyEnum.selectedTools
|
||||
);
|
||||
if (toolConnections.length === 0) {
|
||||
return [data.nodeId];
|
||||
}
|
||||
}
|
||||
|
||||
// check node input
|
||||
if (
|
||||
@@ -506,7 +520,7 @@ export const checkWorkflowNodeAndConnection = ({
|
||||
return [data.nodeId];
|
||||
}
|
||||
|
||||
// filter tools node edge
|
||||
// Check node has invalid edge
|
||||
const edgeFilted = edges.filter(
|
||||
(edge) =>
|
||||
!(
|
||||
@@ -514,7 +528,7 @@ export const checkWorkflowNodeAndConnection = ({
|
||||
edge.sourceHandle === NodeOutputKeyEnum.selectedTools
|
||||
)
|
||||
);
|
||||
// check node has edge
|
||||
// Check node has edge
|
||||
const hasEdge = edgeFilted.some(
|
||||
(edge) => edge.source === data.nodeId || edge.target === data.nodeId
|
||||
);
|
||||
@@ -522,6 +536,106 @@ export const checkWorkflowNodeAndConnection = ({
|
||||
return [data.nodeId];
|
||||
}
|
||||
}
|
||||
|
||||
// Edge check
|
||||
|
||||
/**
|
||||
* Check graph connectivity and identify connectivity issues
|
||||
*/
|
||||
const checkConnectivity = (
|
||||
nodes: Node<FlowNodeItemType, string | undefined>[],
|
||||
edges: Edge<any>[]
|
||||
): string[] => {
|
||||
// Find start node
|
||||
const startNode = nodes.find(
|
||||
(node) =>
|
||||
node.data.flowNodeType === FlowNodeTypeEnum.workflowStart ||
|
||||
node.data.flowNodeType === FlowNodeTypeEnum.pluginInput
|
||||
);
|
||||
|
||||
if (!startNode) {
|
||||
// No start node found - this is a critical issue
|
||||
return nodes.map((node) => node.data.nodeId);
|
||||
}
|
||||
|
||||
const issues: ConnectivityIssue[] = [];
|
||||
|
||||
// Build adjacency lists for both directions
|
||||
const outgoing = new Map<string, string[]>();
|
||||
const incoming = new Map<string, string[]>();
|
||||
|
||||
nodes.forEach((node) => {
|
||||
outgoing.set(node.data.nodeId, []);
|
||||
incoming.set(node.data.nodeId, []);
|
||||
});
|
||||
|
||||
edges.forEach((edge) => {
|
||||
const outList = outgoing.get(edge.source) || [];
|
||||
outList.push(edge.target);
|
||||
outgoing.set(edge.source, outList);
|
||||
|
||||
const inList = incoming.get(edge.target) || [];
|
||||
inList.push(edge.source);
|
||||
incoming.set(edge.target, inList);
|
||||
});
|
||||
|
||||
// Check reachability from start node(Start node/Loop start 可以到达的地方)
|
||||
const reachableFromStart = new Set<string>();
|
||||
const dfsFromStart = (nodeId: string) => {
|
||||
if (reachableFromStart.has(nodeId)) return;
|
||||
reachableFromStart.add(nodeId);
|
||||
|
||||
const neighbors = outgoing.get(nodeId) || [];
|
||||
neighbors.forEach((neighbor) => dfsFromStart(neighbor));
|
||||
};
|
||||
dfsFromStart(startNode.data.nodeId);
|
||||
nodes.forEach((node) => {
|
||||
if (node.data.flowNodeType === FlowNodeTypeEnum.loopStart) {
|
||||
dfsFromStart(node.data.nodeId);
|
||||
}
|
||||
});
|
||||
|
||||
// Check each node for connectivity issues
|
||||
for (const node of nodes) {
|
||||
const nodeId = node.data.nodeId;
|
||||
const nodeType = node.data.flowNodeType;
|
||||
|
||||
// Skip system nodes that don't need connectivity checks
|
||||
if (
|
||||
nodeType === FlowNodeTypeEnum.systemConfig ||
|
||||
nodeType === FlowNodeTypeEnum.pluginConfig ||
|
||||
nodeType === FlowNodeTypeEnum.comment ||
|
||||
nodeType === FlowNodeTypeEnum.globalVariable ||
|
||||
nodeType === FlowNodeTypeEnum.emptyNode
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const hasIncoming = (incoming.get(nodeId) || []).length > 0;
|
||||
const hasOutgoing = (outgoing.get(nodeId) || []).length > 0;
|
||||
const isStartNode = [
|
||||
FlowNodeTypeEnum.workflowStart,
|
||||
FlowNodeTypeEnum.pluginInput,
|
||||
FlowNodeTypeEnum.loopStart
|
||||
].includes(nodeType);
|
||||
|
||||
// Check if node is reachable from start
|
||||
if (!isStartNode && !reachableFromStart.has(nodeId)) {
|
||||
issues.push({
|
||||
nodeId,
|
||||
issue: 'unreachable_from_start'
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return issues.map((issue) => issue.nodeId);
|
||||
};
|
||||
|
||||
const connectivityIssues = checkConnectivity(nodes, edges);
|
||||
if (connectivityIssues.length > 0) {
|
||||
return connectivityIssues;
|
||||
}
|
||||
};
|
||||
|
||||
/* ====== Variables ======= */
|
||||
|
Reference in New Issue
Block a user