Merge branch 'refs/heads/develop' into fix/memory_bug_fix

This commit is contained in:
lixinyue
2026-01-22 20:47:23 +08:00
6 changed files with 31 additions and 9 deletions

View File

@@ -9,7 +9,6 @@ import logging
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Any, AsyncGenerator from typing import Any, AsyncGenerator
from langchain_core.messages import AIMessage
from langgraph.config import get_stream_writer from langgraph.config import get_stream_writer
from typing_extensions import TypedDict, Annotated from typing_extensions import TypedDict, Annotated

View File

@@ -24,6 +24,7 @@ class IterationRuntime:
def __init__( def __init__(
self, self,
start_id: str,
graph: CompiledStateGraph, graph: CompiledStateGraph,
node_id: str, node_id: str,
config: dict[str, Any], config: dict[str, Any],
@@ -38,6 +39,7 @@ class IterationRuntime:
config: Dictionary containing iteration node configuration. config: Dictionary containing iteration node configuration.
state: Current workflow state at the point of iteration. state: Current workflow state at the point of iteration.
""" """
self.start_id = start_id
self.graph = graph self.graph = graph
self.state = state self.state = state
self.node_id = node_id self.node_id = node_id
@@ -70,6 +72,7 @@ class IterationRuntime:
"index": idx, "index": idx,
} }
loopstate["looping"] = True loopstate["looping"] = True
loopstate["activate"][self.start_id] = True
return loopstate return loopstate
async def run_task(self, item, idx): async def run_task(self, item, idx):

View File

@@ -26,6 +26,7 @@ class LoopRuntime:
def __init__( def __init__(
self, self,
start_id: str,
graph: CompiledStateGraph, graph: CompiledStateGraph,
node_id: str, node_id: str,
config: dict[str, Any], config: dict[str, Any],
@@ -40,6 +41,7 @@ class LoopRuntime:
config: Raw configuration dictionary for the loop node. config: Raw configuration dictionary for the loop node.
state: The current workflow state before entering the loop. state: The current workflow state before entering the loop.
""" """
self.start_id = start_id
self.graph = graph self.graph = graph
self.state = state self.state = state
self.node_id = node_id self.node_id = node_id
@@ -87,6 +89,7 @@ class LoopRuntime:
**self.state **self.state
) )
loopstate["looping"] = True loopstate["looping"] = True
loopstate["activate"][self.start_id] = True
return loopstate return loopstate
@staticmethod @staticmethod

View File

@@ -34,7 +34,6 @@ class CycleGraphNode(BaseNode):
self.cycle_nodes = list() # Nodes belonging to this cycle self.cycle_nodes = list() # Nodes belonging to this cycle
self.cycle_edges = list() # Edges connecting nodes within the cycle self.cycle_edges = list() # Edges connecting nodes within the cycle
self.start_node_id = None # ID of the start node within the cycle self.start_node_id = None # ID of the start node within the cycle
self.end_node_ids = [] # IDs of end nodes within the cycle
self.graph: StateGraph | CompiledStateGraph | None = None self.graph: StateGraph | CompiledStateGraph | None = None
self.build_graph() self.build_graph()
@@ -105,13 +104,15 @@ class CycleGraphNode(BaseNode):
""" """
from app.core.workflow.graph_builder import GraphBuilder from app.core.workflow.graph_builder import GraphBuilder
self.cycle_nodes, self.cycle_edges = self.pure_cycle_graph() self.cycle_nodes, self.cycle_edges = self.pure_cycle_graph()
self.graph = GraphBuilder( builder = GraphBuilder(
{ {
"nodes": self.cycle_nodes, "nodes": self.cycle_nodes,
"edges": self.cycle_edges, "edges": self.cycle_edges,
}, },
subgraph=True subgraph=True
).build() )
self.start_node_id = builder.start_node_id
self.graph = builder.build()
async def execute(self, state: WorkflowState) -> Any: async def execute(self, state: WorkflowState) -> Any:
""" """
@@ -132,6 +133,7 @@ class CycleGraphNode(BaseNode):
""" """
if self.node_type == NodeType.LOOP: if self.node_type == NodeType.LOOP:
return await LoopRuntime( return await LoopRuntime(
start_id=self.start_node_id,
graph=self.graph, graph=self.graph,
node_id=self.node_id, node_id=self.node_id,
config=self.config, config=self.config,
@@ -139,6 +141,7 @@ class CycleGraphNode(BaseNode):
).run() ).run()
if self.node_type == NodeType.ITERATION: if self.node_type == NodeType.ITERATION:
return await IterationRuntime( return await IterationRuntime(
start_id=self.start_node_id,
graph=self.graph, graph=self.graph,
node_id=self.node_id, node_id=self.node_id,
config=self.config, config=self.config,

View File

@@ -122,6 +122,11 @@ service.interceptors.response.use(
} }
}, },
(error) => { (error) => {
// 如果是取消请求,不显示错误提示
if (axios.isCancel(error) || error.name === 'AbortError' || error.code === 'ERR_CANCELED') {
return Promise.reject(error);
}
// 处理网络错误、超时等 // 处理网络错误、超时等
let msg = error.response?.data?.error || error.response?.error; let msg = error.response?.data?.error || error.response?.error;
const status = error?.response ? error.response.status : error; const status = error?.response ? error.response.status : error;

View File

@@ -261,15 +261,15 @@ const CreateDataset = () => {
dataIndex: 'progress', dataIndex: 'progress',
key: 'progress', key: 'progress',
render: (value: number, record: any) => { render: (value: number, record: any) => {
// value = 1 时完成01 时显示进度条 // value >= 1 时完成01 时显示进度条
if (value === 1) { if (value >= 1) {
return ( return (
<span className="rb:text-xs rb:border rb:border-[#DFE4ED] rb:bg-[#FBFDFF] rb:rounded rb:items-center rb:text-[#212332] rb:py-1 rb:px-2"> <span className="rb:text-xs rb:border rb:border-[#DFE4ED] rb:bg-[#FBFDFF] rb:rounded rb:items-center rb:text-[#212332] rb:py-1 rb:px-2">
<span className="rb:inline-block rb:w-[5px] rb:h-[5px] rb:mr-2 rb:rounded-full" style={{ backgroundColor: '#369F21' }}></span> <span className="rb:inline-block rb:w-[5px] rb:h-[5px] rb:mr-2 rb:rounded-full" style={{ backgroundColor: '#369F21' }}></span>
<span>{t('knowledgeBase.completed')}</span> <span>{t('knowledgeBase.completed')}</span>
</span> </span>
); );
} else if (value > 0 && value < 1) { } else if (value >= 0 && value < 1) {
// 处理中,显示进度条 // 处理中,显示进度条
return ( return (
<div className="rb:flex rb:items-center rb:gap-2"> <div className="rb:flex rb:items-center rb:gap-2">
@@ -277,7 +277,10 @@ const CreateDataset = () => {
percent={Math.round(value * 100)} percent={Math.round(value * 100)}
size="small" size="small"
status="active" status="active"
strokeColor="#1677ff" strokeColor={{
'0%': '#108ee9',
'100%': '#87d068',
}}
style={{ width: '120px' }} style={{ width: '120px' }}
/> />
</div> </div>
@@ -383,6 +386,9 @@ const CreateDataset = () => {
}, },
}) })
.then((res: UploadFileResponse) => { .then((res: UploadFileResponse) => {
// 上传成功,移除 AbortController
abortControllersRef.current.delete(fileUid);
onSuccess?.(res, new XMLHttpRequest()); onSuccess?.(res, new XMLHttpRequest());
if (res?.id) { if (res?.id) {
setRechunkFileIds((prev) => { setRechunkFileIds((prev) => {
@@ -578,6 +584,8 @@ const CreateDataset = () => {
abortController.abort(); abortController.abort();
abortControllersRef.current.delete(fileUid); abortControllersRef.current.delete(fileUid);
console.log('已取消上传:', (file as any).name); console.log('已取消上传:', (file as any).name);
// 取消上传后直接返回 true允许移除文件
return true;
} }
// 只有当文件已经上传成功有response.id才删除服务器上的文件 // 只有当文件已经上传成功有response.id才删除服务器上的文件
@@ -586,6 +594,7 @@ const CreateDataset = () => {
await deleteDocument(file.response.id); await deleteDocument(file.response.id);
setRechunkFileIds(prev => prev.filter(id => id !== file.response.id)); setRechunkFileIds(prev => prev.filter(id => id !== file.response.id));
console.log('已删除服务器文件:', file.response.id); console.log('已删除服务器文件:', file.response.id);
return true;
} catch (error) { } catch (error) {
console.error('删除文件失败:', error); console.error('删除文件失败:', error);
messageApi.error(t('common.deleteFailed') || '删除文件失败'); messageApi.error(t('common.deleteFailed') || '删除文件失败');
@@ -593,7 +602,7 @@ const CreateDataset = () => {
} }
} }
// 允许移除文件(无论是取消上传还是删除成功) // 其他情况(如上传失败的文件)也允许移除
return true; return true;
}} /> }} />
)} )}