Merge branch 'refs/heads/develop' into fix/memory_bug_fix
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 时完成,0~1 时显示进度条
|
// value >= 1 时完成,0~1 时显示进度条
|
||||||
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;
|
||||||
}} />
|
}} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user