balibabu commited on
Commit
369d05c
·
1 Parent(s): c298fc4

feat: construct the edge of the classification operator from dsl #918 (#1329)

Browse files

### What problem does this PR solve?

feat: construct the edge of the classification operator from dsl #918

### Type of change


- [x] New Feature (non-breaking change which adds functionality)

graph/test/dsl_examples/headhunter_zh.json CHANGED
@@ -1,194 +1,210 @@
1
  {
2
  "components": {
3
- "begin": {
4
- "obj":{
5
- "component_name": "Begin",
6
- "params": {
7
- "prologue": "您好!我是AGI方向的猎头,了解到您是这方面的大佬,然后冒昧的就联系到您。这边有个机会想和您分享,RAGFlow正在招聘您这个岗位的资深的工程师不知道您那边是不是感兴趣?"
8
- }
9
- },
10
- "downstream": ["answer:0"],
11
- "upstream": []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  },
13
- "answer:0": {
14
- "obj": {
15
- "component_name": "Answer",
16
- "params": {}
17
- },
18
- "downstream": ["categorize:0"],
19
- "upstream": ["begin", "message:reject"]
20
  },
21
- "categorize:0": {
22
- "obj": {
23
- "component_name": "Categorize",
24
- "params": {
25
- "llm_id": "deepseek-chat",
26
- "category_description": {
27
- "about_job": {
28
- "description": "该问题关于职位本身或公司的信息。",
29
- "examples": "什么岗位?\n汇报对象是谁?\n公司多少人?\n公司有啥产品?\n具体工作内容是啥?\n地点哪里?\n双休吗?",
30
- "to": "retrieval:0"
31
- },
32
- "casual": {
33
- "description": "该问题不关于职位本身或公司的信息,属于闲聊。",
34
- "examples": "你好\n好久不见\n你男的女的?\n你是猴子派来的救兵吗?\n上午开会了?\n你叫啥?\n最近市场如何?生意好做吗?",
35
- "to": "generate:casual"
36
- },
37
- "interested": {
38
- "description": "该回答表示他对于该职位感兴趣。",
39
- "examples": "嗯\n说吧\n说说看\n还好吧\n是的\n哦\nyes\n具体说说",
40
- "to": "message:introduction"
41
- },
42
- "answer": {
43
- "description": "该回答表示他对于该职位不感兴趣,或感觉受到骚扰。",
44
- "examples": "不需要\n不感兴趣\n暂时不看\n不要\nno\n我已经不干这个了\n我不是这个方向的",
45
- "to": "message:reject"
46
- }
47
- }
48
- }
49
- },
50
- "downstream": ["message:introduction", "generate:casual", "message:reject", "retrieval:0"],
51
- "upstream": ["answer:0"]
52
  },
53
- "message:introduction": {
54
- "obj":{
55
- "component_name": "Message",
56
- "params": {
57
- "messages": [
58
- "我简单介绍以下:\nRAGFlow 是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不同的复杂格式数据提供可靠的问答以及有理有据的引用。https://github.com/infiniflow/ragflow\n您那边还有什么要了解的?"
59
- ]
60
- }
61
- },
62
- "downstream": ["answer:1"],
63
- "upstream": ["categorize:0"]
64
- },
65
- "answer:1": {
66
- "obj": {
67
- "component_name": "Answer",
68
- "params": {}
69
- },
70
- "downstream": ["categorize:1"],
71
- "upstream": ["message:introduction", "generate:aboutJob", "generate:casual", "generate:get_wechat", "generate:nowechat"]
72
- },
73
- "categorize:1": {
74
- "obj": {
75
- "component_name": "Categorize",
76
- "params": {
77
- "llm_id": "deepseek-chat",
78
- "category_description": {
79
- "about_job": {
80
- "description": "该问题关于职位本身或公司的信息。",
81
- "examples": "什么岗位?\n汇报对象是谁?\n公司多少人?\n公司有啥产品?\n具体工作内容是啥?\n地点哪里?\n双休吗?",
82
- "to": "retrieval:0"
83
- },
84
- "casual": {
85
- "description": "该问题不关于职位本身或公司的信息,属于闲聊。",
86
- "examples": "你好\n好久不见\n你男的女的?\n你是猴子派来的救兵吗?\n上午开会了?\n你叫啥?\n最近市场如何?生意好做吗?",
87
- "to": "generate:casual"
88
- },
89
- "wechat": {
90
- "description": "该回答表示他愿意加微信,或者已经报了微信号。",
91
- "examples": "嗯\n可以\n是的\n哦\nyes\n15002333453\nwindblow_2231",
92
- "to": "generate:get_wechat"
93
- },
94
- "giveup": {
95
- "description": "该回答表示他不愿意加微信。",
96
- "examples": "不需要\n不感兴趣\n暂时不看\n不要\nno\n不方便\n不知道还要加我微信",
97
- "to": "generate:nowechat"
98
- }
99
- },
100
- "message_history_window_size": 8
101
- }
102
- },
103
- "downstream": ["retrieval:0", "generate:casual", "generate:get_wechat", "generate:nowechat"],
104
- "upstream": ["answer:0"]
105
- },
106
- "generate:casual": {
107
- "obj": {
108
- "component_name": "Generate",
109
- "params": {
110
- "llm_id": "deepseek-chat",
111
- "prompt": "你是AGI方向的猎头,现在候选人的聊了和职位无关的话题,请耐心的回应候选人,并将话题往该AGI的职位上带,最好能要到候选人微信号以便后面保持联系。",
112
- "temperature": 0.9,
113
- "message_history_window_size": 12,
114
- "cite": false
115
- }
116
- },
117
- "downstream": ["answer:1"],
118
- "upstream": ["categorize:0", "categorize:1"]
119
- },
120
- "retrieval:0": {
121
- "obj": {
122
- "component_name": "Retrieval",
123
- "params": {
124
- "similarity_threshold": 0.2,
125
- "keywords_similarity_weight": 0.3,
126
- "top_n": 6,
127
- "top_k": 1024,
128
- "rerank_id": "BAAI/bge-reranker-v2-m3",
129
- "kb_ids": ["869a236818b811ef91dffa163e197198"]
130
- }
131
- },
132
- "downstream": ["generate:aboutJob"],
133
- "upstream": ["categorize:0", "categorize:1"]
134
- },
135
- "generate:aboutJob": {
136
- "obj": {
137
- "component_name": "Generate",
138
- "params": {
139
- "llm_id": "deepseek-chat",
140
- "prompt": "你是AGI方向的猎头,候选人问了有关职位或公司的问题,你根据以下职位信息回答。如果职位信息中不包含候选人的问题就回答不清楚、不知道、有待确认等。回答完后引导候选人加微信号,如:\n - 方便加一下微信吗,我把JD发您看看?\n - 微信号多少,我把详细职位JD发您?\n 职位信息如下:\n {input}\n 职位信息如上。",
141
- "temperature": 0.02
142
- }
143
- },
144
- "downstream": ["answer:1"],
145
- "upstream": ["relevant:0"]
146
  },
147
- "generate:get_wechat": {
148
- "obj": {
149
- "component_name": "Generate",
150
- "params": {
151
- "llm_id": "deepseek-chat",
152
- "prompt": "你是AGI方向的猎头,候选人表示不反感加微信,如果对方已经报了微信号,表示感谢和信任并表示马上会加上;如果没有,则问对方微信号多少。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
153
- "temperature": 0.1,
154
- "message_history_window_size": 12,
155
- "cite": false
156
- }
157
- },
158
- "downstream": ["answer:1"],
159
- "upstream": ["categorize:1"]
160
  },
161
- "generate:nowechat": {
162
- "obj":{
163
- "component_name": "Generate",
164
- "params": {
165
- "llm_id": "deepseek-chat",
166
- "prompt": "你是AGI方向的猎头,当你提出加微信时对方表示拒绝。你需要耐心礼貌的回应候选人,表示对于保护隐私信息给予理解,也可以询问他对该职位的看法和顾虑。并在恰当的时机再次询问微信联系方式。也可以鼓励候选人主动与你取得联系。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
167
- "temperature": 0.1,
168
- "message_history_window_size": 12,
169
- "cite": false
170
- }
171
- },
172
- "downstream": ["answer:1"],
173
- "upstream": ["categorize:1"]
174
  },
175
- "message:reject": {
176
- "obj":{
177
- "component_name": "Message",
178
- "params": {
179
- "messages": [
180
- "好的,祝您生活愉快,工作顺利。",
181
- "哦,好的,感谢您宝贵的时间!"
182
- ]
183
- }
184
- },
185
- "downstream": ["answer:0"],
186
- "upstream": ["categorize:0"]
187
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  },
189
  "history": [],
190
  "messages": [],
191
  "path": [],
192
  "reference": {},
193
  "answer": []
194
- }
 
1
  {
2
  "components": {
3
+ "begin": {
4
+ "obj": {
5
+ "component_name": "Begin",
6
+ "params": {
7
+ "prologue": "您好!我是AGI方向的猎头,了解到您是这方面的大佬,然后冒昧的就联系到您。这边有个机会想和您分享,RAGFlow正在招聘您这个岗位的资深的工程师不知道您那边是不是感兴趣?"
8
+ }
9
+ },
10
+ "downstream": ["answer:0"],
11
+ "upstream": []
12
+ },
13
+ "answer:0": {
14
+ "obj": {
15
+ "component_name": "Answer",
16
+ "params": {}
17
+ },
18
+ "downstream": ["categorize:0"],
19
+ "upstream": ["begin", "message:reject"]
20
+ },
21
+ "categorize:0": {
22
+ "obj": {
23
+ "component_name": "Categorize",
24
+ "params": {
25
+ "llm_id": "deepseek-chat",
26
+ "category_description": {
27
+ "about_job": {
28
+ "description": "该问题关于职位本身或公司的信息。",
29
+ "examples": "什么岗位?\n汇报对象是谁?\n公司多少人?\n公司有啥产品?\n具体工作内容是啥?\n地点哪里?\n双休吗?",
30
+ "to": "retrieval:0"
31
  },
32
+ "casual": {
33
+ "description": "该问题不关于职位本身或公司的信息,属于闲聊。",
34
+ "examples": "你好\n好久不见\n你男的女的?\n你是猴子派来的救兵吗?\n上午开会了?\n你叫啥?\n最近市场如何?生意好做吗?",
35
+ "to": "generate:casual"
 
 
 
36
  },
37
+ "interested": {
38
+ "description": "该回答表示他对于该职位感兴趣。",
39
+ "examples": "嗯\n说吧\n说说看\n还好吧\n是的\n哦\nyes\n具体说说",
40
+ "to": "message:introduction"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  },
42
+ "answer": {
43
+ "description": "该回答表示他对于该职位不感兴趣,或感觉受到骚扰。",
44
+ "examples": "不需要\n不感兴趣\n暂时不看\n不要\nno\n我已经不干这个了\n我不是这个方向的",
45
+ "to": "message:reject"
46
+ }
47
+ }
48
+ }
49
+ },
50
+ "downstream": [
51
+ "message:introduction",
52
+ "generate:casual",
53
+ "message:reject",
54
+ "retrieval:0"
55
+ ],
56
+ "upstream": ["answer:0"]
57
+ },
58
+ "message:introduction": {
59
+ "obj": {
60
+ "component_name": "Message",
61
+ "params": {
62
+ "messages": [
63
+ "我简单介绍以下:\nRAGFlow 是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不同的复杂格式数据提供可靠的问答以及有理有据的引用。https://github.com/infiniflow/ragflow\n您那边还有什么要了解的?"
64
+ ]
65
+ }
66
+ },
67
+ "downstream": ["answer:1"],
68
+ "upstream": ["categorize:0"]
69
+ },
70
+ "answer:1": {
71
+ "obj": {
72
+ "component_name": "Answer",
73
+ "params": {}
74
+ },
75
+ "downstream": ["categorize:1"],
76
+ "upstream": [
77
+ "message:introduction",
78
+ "generate:aboutJob",
79
+ "generate:casual",
80
+ "generate:get_wechat",
81
+ "generate:nowechat"
82
+ ]
83
+ },
84
+ "categorize:1": {
85
+ "obj": {
86
+ "component_name": "Categorize",
87
+ "params": {
88
+ "llm_id": "deepseek-chat",
89
+ "category_description": {
90
+ "about_job": {
91
+ "description": "该问题关于职位本身或公司的信息。",
92
+ "examples": "什么岗位?\n汇报对象是谁?\n公司多少人?\n公司有啥产品?\n具体工作内容是啥?\n地点哪里?\n双休吗?",
93
+ "to": "retrieval:0"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  },
95
+ "casual": {
96
+ "description": "该问题不关于职位本身或公司的信息,属于闲聊。",
97
+ "examples": "你好\n好久不见\n你男的女的?\n你是猴子派来的救兵吗?\n上午开会了?\n你叫啥?\n最近市场如何?生意好做吗?",
98
+ "to": "generate:casual"
 
 
 
 
 
 
 
 
 
99
  },
100
+ "wechat": {
101
+ "description": "该回答表示他愿意加微信,或者已经报了微信号。",
102
+ "examples": "嗯\n可以\n是的\n哦\nyes\n15002333453\nwindblow_2231",
103
+ "to": "generate:get_wechat"
 
 
 
 
 
 
 
 
 
104
  },
105
+ "giveup": {
106
+ "description": "该回答表示他不愿意加微信。",
107
+ "examples": "不需要\n不感兴趣\n暂时不看\n不要\nno\n不方便\n不知道还要加我微信",
108
+ "to": "generate:nowechat"
 
 
 
 
 
 
 
 
109
  }
110
+ },
111
+ "message_history_window_size": 8
112
+ }
113
+ },
114
+ "downstream": [
115
+ "retrieval:0",
116
+ "generate:casual",
117
+ "generate:get_wechat",
118
+ "generate:nowechat"
119
+ ],
120
+ "upstream": ["answer:1"]
121
+ },
122
+ "generate:casual": {
123
+ "obj": {
124
+ "component_name": "Generate",
125
+ "params": {
126
+ "llm_id": "deepseek-chat",
127
+ "prompt": "你是AGI方向的猎头,现在候选人的聊了和职位无关的话题,请耐心的回应候选人,并将话题往该AGI的职位上带,最好能要到候选人微信号以便后面保持联系。",
128
+ "temperature": 0.9,
129
+ "message_history_window_size": 12,
130
+ "cite": false
131
+ }
132
+ },
133
+ "downstream": ["answer:1"],
134
+ "upstream": ["categorize:0", "categorize:1"]
135
+ },
136
+ "retrieval:0": {
137
+ "obj": {
138
+ "component_name": "Retrieval",
139
+ "params": {
140
+ "similarity_threshold": 0.2,
141
+ "keywords_similarity_weight": 0.3,
142
+ "top_n": 6,
143
+ "top_k": 1024,
144
+ "rerank_id": "BAAI/bge-reranker-v2-m3",
145
+ "kb_ids": ["869a236818b811ef91dffa163e197198"]
146
+ }
147
+ },
148
+ "downstream": ["generate:aboutJob"],
149
+ "upstream": ["categorize:0", "categorize:1"]
150
+ },
151
+ "generate:aboutJob": {
152
+ "obj": {
153
+ "component_name": "Generate",
154
+ "params": {
155
+ "llm_id": "deepseek-chat",
156
+ "prompt": "你是AGI方向的猎头,候选人问了有关职位或公司的问题,你根据以下职位信息回答。如果职位信息中不包含候选人的问题就回答不清楚、不知道、有待确认等。回答完后引导候选人加微信号,如:\n - 方便加一下微信吗,我把JD发您看看?\n - 微信号多少,我把详细职位JD发您?\n 职位信息如下:\n {input}\n 职位信息如上。",
157
+ "temperature": 0.02
158
+ }
159
+ },
160
+ "downstream": ["answer:1"],
161
+ "upstream": ["relevant:0"]
162
+ },
163
+ "generate:get_wechat": {
164
+ "obj": {
165
+ "component_name": "Generate",
166
+ "params": {
167
+ "llm_id": "deepseek-chat",
168
+ "prompt": "你是AGI方向的猎头,候选人表示不反感加微信,如果对方已经报了微信号,表示感谢和信任并表示马上会加上;如果没有,则问对方微信号多少。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
169
+ "temperature": 0.1,
170
+ "message_history_window_size": 12,
171
+ "cite": false
172
+ }
173
+ },
174
+ "downstream": ["answer:1"],
175
+ "upstream": ["categorize:1"]
176
+ },
177
+ "generate:nowechat": {
178
+ "obj": {
179
+ "component_name": "Generate",
180
+ "params": {
181
+ "llm_id": "deepseek-chat",
182
+ "prompt": "你是AGI方向的猎头,当你提出加微信时对方表示拒绝。你需要耐心礼貌的回应候选人,表示对于保护隐私信息给予理解,也可以询问他对该职位的看法和顾虑。并在恰当的时机再次询问微信联系方式。也可以鼓励候选人主动与你取得联系。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
183
+ "temperature": 0.1,
184
+ "message_history_window_size": 12,
185
+ "cite": false
186
+ }
187
+ },
188
+ "downstream": ["answer:1"],
189
+ "upstream": ["categorize:1"]
190
+ },
191
+ "message:reject": {
192
+ "obj": {
193
+ "component_name": "Message",
194
+ "params": {
195
+ "messages": [
196
+ "好的,祝您生活愉快,工作顺利。",
197
+ "哦,好的,感谢您宝贵的时间!"
198
+ ]
199
+ }
200
+ },
201
+ "downstream": ["answer:0"],
202
+ "upstream": ["categorize:0"]
203
+ }
204
  },
205
  "history": [],
206
  "messages": [],
207
  "path": [],
208
  "reference": {},
209
  "answer": []
210
+ }
web/src/pages/flow/canvas/node/categorize-node.tsx CHANGED
@@ -24,6 +24,21 @@ export function CategorizeNode({ id, data, selected }: NodeProps<NodeData>) {
24
  position={Position.Left}
25
  isConnectable
26
  className={styles.handle}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  ></Handle>
28
  {Object.keys(categoryData).map((x, idx) => (
29
  <CategorizeHandle
 
24
  position={Position.Left}
25
  isConnectable
26
  className={styles.handle}
27
+ id={'a'}
28
+ ></Handle>
29
+ <Handle
30
+ type="target"
31
+ position={Position.Top}
32
+ isConnectable
33
+ className={styles.handle}
34
+ id={'b'}
35
+ ></Handle>
36
+ <Handle
37
+ type="target"
38
+ position={Position.Bottom}
39
+ isConnectable
40
+ className={styles.handle}
41
+ id={'c'}
42
  ></Handle>
43
  {Object.keys(categoryData).map((x, idx) => (
44
  <CategorizeHandle
web/src/pages/flow/canvas/node/index.less CHANGED
@@ -28,7 +28,7 @@
28
  }
29
  .bottomBox {
30
  position: absolute;
31
- bottom: -24px;
32
  background: white;
33
  padding: 2px 5px;
34
  border-radius: 5px;
 
28
  }
29
  .bottomBox {
30
  position: absolute;
31
+ bottom: -26px;
32
  background: white;
33
  padding: 2px 5px;
34
  border-radius: 5px;
web/src/pages/flow/headhunter_zh.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "edges": [
3
  {
4
- "id": "1a75afcd-05ea-4bf1-af5e-adff4f870100",
5
  "label": "",
6
  "source": "begin",
7
  "target": "answer:0",
@@ -10,7 +10,7 @@
10
  }
11
  },
12
  {
13
- "id": "a88e567e-1c23-457f-a0db-a90f1ea14d21",
14
  "label": "",
15
  "source": "message:reject",
16
  "target": "answer:0",
@@ -19,7 +19,7 @@
19
  }
20
  },
21
  {
22
- "id": "ad5fdb81-568e-46c5-82b1-1f50b625ae23",
23
  "label": "",
24
  "source": "answer:0",
25
  "target": "categorize:0",
@@ -28,43 +28,47 @@
28
  }
29
  },
30
  {
31
- "id": "fbb4c147-0d4c-4dd2-9264-3088e02c40d1",
32
  "label": "",
33
  "source": "categorize:0",
34
  "target": "message:introduction",
35
  "markerEnd": {
36
  "type": "arrow"
37
- }
 
38
  },
39
  {
40
- "id": "40da6d94-7d51-4d77-a5dd-1d583daba147",
41
  "label": "",
42
  "source": "categorize:0",
43
  "target": "generate:casual",
44
  "markerEnd": {
45
  "type": "arrow"
46
- }
 
47
  },
48
  {
49
- "id": "e4c7f5dc-5ccb-45da-af0d-4fbcb9dbb6f9",
50
  "label": "",
51
  "source": "categorize:0",
52
  "target": "message:reject",
53
  "markerEnd": {
54
  "type": "arrow"
55
- }
 
56
  },
57
  {
58
- "id": "a8c0b4e5-9597-4335-bded-5b1dd46f7507",
59
  "label": "",
60
  "source": "categorize:0",
61
  "target": "retrieval:0",
62
  "markerEnd": {
63
  "type": "arrow"
64
- }
 
65
  },
66
  {
67
- "id": "223972c4-08f7-47ae-b9ce-9a52dba044a7",
68
  "label": "",
69
  "source": "message:introduction",
70
  "target": "answer:1",
@@ -73,7 +77,7 @@
73
  }
74
  },
75
  {
76
- "id": "ece123ba-a84c-41d6-a843-63df331f945e",
77
  "label": "",
78
  "source": "generate:aboutJob",
79
  "target": "answer:1",
@@ -82,7 +86,7 @@
82
  }
83
  },
84
  {
85
- "id": "fa07af7d-29de-4066-89b7-f1bee184e260",
86
  "label": "",
87
  "source": "generate:casual",
88
  "target": "answer:1",
@@ -91,7 +95,7 @@
91
  }
92
  },
93
  {
94
- "id": "0d7565d8-673c-4a5e-90f4-f4296384eef0",
95
  "label": "",
96
  "source": "generate:get_wechat",
97
  "target": "answer:1",
@@ -100,7 +104,7 @@
100
  }
101
  },
102
  {
103
- "id": "e615e3d2-8ba5-448f-b001-ab926078cca6",
104
  "label": "",
105
  "source": "generate:nowechat",
106
  "target": "answer:1",
@@ -109,7 +113,7 @@
109
  }
110
  },
111
  {
112
- "id": "a9cf0f0a-77b5-42a2-a71f-e71086a525f0",
113
  "label": "",
114
  "source": "answer:1",
115
  "target": "categorize:1",
@@ -118,52 +122,47 @@
118
  }
119
  },
120
  {
121
- "id": "4e4c5461-cdc6-46c1-afb1-5892cb54104a",
122
- "label": "",
123
- "source": "answer:0",
124
- "target": "categorize:1",
125
- "markerEnd": {
126
- "type": "arrow"
127
- }
128
- },
129
- {
130
- "id": "44c8cb42-a2d9-43df-83bb-175d4870a027",
131
  "label": "",
132
  "source": "categorize:1",
133
  "target": "retrieval:0",
134
  "markerEnd": {
135
  "type": "arrow"
136
- }
 
137
  },
138
  {
139
- "id": "86d2308d-c91a-4a21-a6d6-081c92fc517c",
140
  "label": "",
141
  "source": "categorize:1",
142
  "target": "generate:casual",
143
  "markerEnd": {
144
  "type": "arrow"
145
- }
 
146
  },
147
  {
148
- "id": "e5de8fc4-b801-44cf-8240-02f2aac6ae23",
149
  "label": "",
150
  "source": "categorize:1",
151
  "target": "generate:get_wechat",
152
  "markerEnd": {
153
  "type": "arrow"
154
- }
 
155
  },
156
  {
157
- "id": "a9511914-d696-46b4-90c2-a3a940205b5c",
158
  "label": "",
159
  "source": "categorize:1",
160
  "target": "generate:nowechat",
161
  "markerEnd": {
162
  "type": "arrow"
163
- }
 
164
  },
165
  {
166
- "id": "07db19d7-e356-4c24-8e0d-353b1e6e6ee4",
167
  "label": "",
168
  "source": "retrieval:0",
169
  "target": "generate:aboutJob",
@@ -172,7 +171,7 @@
172
  }
173
  },
174
  {
175
- "id": "e17eb04f-c773-44b2-8a7b-7f770185c4fa",
176
  "label": "",
177
  "source": "relevant:0",
178
  "target": "generate:aboutJob",
@@ -191,11 +190,9 @@
191
  },
192
  "data": {
193
  "label": "Begin",
194
- "params": {
195
  "prologue": "您好!我是AGI方向的猎头,了解到您是这方面的大佬,然后冒昧的就联系到您。这边有个机会想和您分享,RAGFlow正在招聘您这个岗位的资深的工程师不知道您那边是不是感兴趣?"
196
- },
197
- "downstream": ["answer:0"],
198
- "upstream": []
199
  },
200
  "sourcePosition": "left",
201
  "targetPosition": "right"
@@ -209,9 +206,7 @@
209
  },
210
  "data": {
211
  "label": "Answer",
212
- "params": {},
213
- "downstream": ["categorize:0"],
214
- "upstream": ["begin", "message:reject"]
215
  },
216
  "sourcePosition": "left",
217
  "targetPosition": "right"
@@ -225,7 +220,7 @@
225
  },
226
  "data": {
227
  "label": "Categorize",
228
- "params": {
229
  "llm_id": "deepseek-chat",
230
  "category_description": {
231
  "about_job": {
@@ -249,14 +244,7 @@
249
  "to": "message:reject"
250
  }
251
  }
252
- },
253
- "downstream": [
254
- "message:introduction",
255
- "generate:casual",
256
- "message:reject",
257
- "retrieval:0"
258
- ],
259
- "upstream": ["answer:0"]
260
  },
261
  "sourcePosition": "left",
262
  "targetPosition": "right"
@@ -270,13 +258,11 @@
270
  },
271
  "data": {
272
  "label": "Message",
273
- "params": {
274
  "messages": [
275
  "我简单介绍以下:\nRAGFlow 是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不同的复杂格式数据提供可靠的问答以及有理有据的引用。https://github.com/infiniflow/ragflow\n您那边还有什么要了解的?"
276
  ]
277
- },
278
- "downstream": ["answer:1"],
279
- "upstream": ["categorize:0"]
280
  },
281
  "sourcePosition": "left",
282
  "targetPosition": "right"
@@ -290,15 +276,7 @@
290
  },
291
  "data": {
292
  "label": "Answer",
293
- "params": {},
294
- "downstream": ["categorize:1"],
295
- "upstream": [
296
- "message:introduction",
297
- "generate:aboutJob",
298
- "generate:casual",
299
- "generate:get_wechat",
300
- "generate:nowechat"
301
- ]
302
  },
303
  "sourcePosition": "left",
304
  "targetPosition": "right"
@@ -312,7 +290,7 @@
312
  },
313
  "data": {
314
  "label": "Categorize",
315
- "params": {
316
  "llm_id": "deepseek-chat",
317
  "category_description": {
318
  "about_job": {
@@ -337,14 +315,7 @@
337
  }
338
  },
339
  "message_history_window_size": 8
340
- },
341
- "downstream": [
342
- "retrieval:0",
343
- "generate:casual",
344
- "generate:get_wechat",
345
- "generate:nowechat"
346
- ],
347
- "upstream": ["answer:0"]
348
  },
349
  "sourcePosition": "left",
350
  "targetPosition": "right"
@@ -358,15 +329,13 @@
358
  },
359
  "data": {
360
  "label": "Generate",
361
- "params": {
362
  "llm_id": "deepseek-chat",
363
  "prompt": "你是AGI方向的猎头,现在候选人的聊了和职位无关的话题,请耐心的回应候选人,并将话题往该AGI的职位上带,最好能要到候选人微信号以便后面保持联系。",
364
  "temperature": 0.9,
365
  "message_history_window_size": 12,
366
  "cite": false
367
- },
368
- "downstream": ["answer:1"],
369
- "upstream": ["categorize:0", "categorize:1"]
370
  },
371
  "sourcePosition": "left",
372
  "targetPosition": "right"
@@ -380,16 +349,14 @@
380
  },
381
  "data": {
382
  "label": "Retrieval",
383
- "params": {
384
  "similarity_threshold": 0.2,
385
  "keywords_similarity_weight": 0.3,
386
  "top_n": 6,
387
  "top_k": 1024,
388
  "rerank_id": "BAAI/bge-reranker-v2-m3",
389
  "kb_ids": ["869a236818b811ef91dffa163e197198"]
390
- },
391
- "downstream": ["generate:aboutJob"],
392
- "upstream": ["categorize:0", "categorize:1"]
393
  },
394
  "sourcePosition": "left",
395
  "targetPosition": "right"
@@ -403,13 +370,11 @@
403
  },
404
  "data": {
405
  "label": "Generate",
406
- "params": {
407
  "llm_id": "deepseek-chat",
408
  "prompt": "你是AGI方向的猎头,候选人问了有关职位或公司的问题,你根据以下职位信息回答。如果职位信息中不包含候选人的问题就回答不清楚、不知道、有待确认等。回答完后引导候选人加微信号,如:\n - 方便加一下微信吗,我把JD发您看看?\n - 微信号多少,我把详细职位JD发您?\n 职位信息如下:\n {input}\n 职位信息如上。",
409
  "temperature": 0.02
410
- },
411
- "downstream": ["answer:1"],
412
- "upstream": ["relevant:0"]
413
  },
414
  "sourcePosition": "left",
415
  "targetPosition": "right"
@@ -423,15 +388,13 @@
423
  },
424
  "data": {
425
  "label": "Generate",
426
- "params": {
427
  "llm_id": "deepseek-chat",
428
  "prompt": "你是AGI方向的猎头,候选人表示不反感加微信,如果对方已经报了微信号,表示感谢和信任并表示马上会加上;如果没有,则问对方微信号多少。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
429
  "temperature": 0.1,
430
  "message_history_window_size": 12,
431
  "cite": false
432
- },
433
- "downstream": ["answer:1"],
434
- "upstream": ["categorize:1"]
435
  },
436
  "sourcePosition": "left",
437
  "targetPosition": "right"
@@ -445,15 +408,13 @@
445
  },
446
  "data": {
447
  "label": "Generate",
448
- "params": {
449
  "llm_id": "deepseek-chat",
450
  "prompt": "你是AGI方向的猎头,当你提出加微信时对方表示拒绝。你需要耐心礼貌的回应候选人,表示对于保护隐私信息给予理解,也可以询问他对该职位的看法和顾虑。并在恰当的时机再次询问微信联系方式。也可以鼓励候选人主动与你取得联系。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
451
  "temperature": 0.1,
452
  "message_history_window_size": 12,
453
  "cite": false
454
- },
455
- "downstream": ["answer:1"],
456
- "upstream": ["categorize:1"]
457
  },
458
  "sourcePosition": "left",
459
  "targetPosition": "right"
@@ -467,14 +428,12 @@
467
  },
468
  "data": {
469
  "label": "Message",
470
- "params": {
471
  "messages": [
472
  "好的,祝您生活愉快,工作顺利。",
473
  "哦,好的,感谢您宝贵的时间!"
474
  ]
475
- },
476
- "downstream": ["answer:0"],
477
- "upstream": ["categorize:0"]
478
  },
479
  "sourcePosition": "left",
480
  "targetPosition": "right"
 
1
  {
2
  "edges": [
3
  {
4
+ "id": "f42b5218-8052-4eb5-9cec-2dd302ad478a",
5
  "label": "",
6
  "source": "begin",
7
  "target": "answer:0",
 
10
  }
11
  },
12
  {
13
+ "id": "84c024e1-a96f-438c-905f-63ef725b0442",
14
  "label": "",
15
  "source": "message:reject",
16
  "target": "answer:0",
 
19
  }
20
  },
21
  {
22
+ "id": "04b4bf3c-1f49-4cd8-9b93-779c9d8aa86c",
23
  "label": "",
24
  "source": "answer:0",
25
  "target": "categorize:0",
 
28
  }
29
  },
30
  {
31
+ "id": "0c1ac8d3-9a45-44b1-92e1-f7e3f1b3be9b",
32
  "label": "",
33
  "source": "categorize:0",
34
  "target": "message:introduction",
35
  "markerEnd": {
36
  "type": "arrow"
37
+ },
38
+ "sourceHandle": "interested"
39
  },
40
  {
41
+ "id": "309d9f73-f125-44aa-be84-e716dffb4af1",
42
  "label": "",
43
  "source": "categorize:0",
44
  "target": "generate:casual",
45
  "markerEnd": {
46
  "type": "arrow"
47
+ },
48
+ "sourceHandle": "casual"
49
  },
50
  {
51
+ "id": "d8f39ec9-b993-42c7-aa88-e86192c8ee14",
52
  "label": "",
53
  "source": "categorize:0",
54
  "target": "message:reject",
55
  "markerEnd": {
56
  "type": "arrow"
57
+ },
58
+ "sourceHandle": "answer"
59
  },
60
  {
61
+ "id": "34047c0a-6c50-4cf7-a2e6-d1a8cd9b269b",
62
  "label": "",
63
  "source": "categorize:0",
64
  "target": "retrieval:0",
65
  "markerEnd": {
66
  "type": "arrow"
67
+ },
68
+ "sourceHandle": "about_job"
69
  },
70
  {
71
+ "id": "0613a366-8476-44a5-8b6c-874007de7d5c",
72
  "label": "",
73
  "source": "message:introduction",
74
  "target": "answer:1",
 
77
  }
78
  },
79
  {
80
+ "id": "b14d80a7-3e63-4ba4-bfb2-80ad3a1b5980",
81
  "label": "",
82
  "source": "generate:aboutJob",
83
  "target": "answer:1",
 
86
  }
87
  },
88
  {
89
+ "id": "6126fd77-f407-4ce5-966b-62cb18011343",
90
  "label": "",
91
  "source": "generate:casual",
92
  "target": "answer:1",
 
95
  }
96
  },
97
  {
98
+ "id": "24c6cc93-7f0d-4fae-a54d-a2a79336f58e",
99
  "label": "",
100
  "source": "generate:get_wechat",
101
  "target": "answer:1",
 
104
  }
105
  },
106
  {
107
+ "id": "f09d9bf3-d64c-4a23-a415-c53179e7366f",
108
  "label": "",
109
  "source": "generate:nowechat",
110
  "target": "answer:1",
 
113
  }
114
  },
115
  {
116
+ "id": "cd55cf28-ddac-476e-a73e-d6c0d54f62d2",
117
  "label": "",
118
  "source": "answer:1",
119
  "target": "categorize:1",
 
122
  }
123
  },
124
  {
125
+ "id": "69ad4e49-c538-4406-900c-352644fde6b9",
 
 
 
 
 
 
 
 
 
126
  "label": "",
127
  "source": "categorize:1",
128
  "target": "retrieval:0",
129
  "markerEnd": {
130
  "type": "arrow"
131
+ },
132
+ "sourceHandle": "about_job"
133
  },
134
  {
135
+ "id": "999c5601-e69d-4a35-a15e-474546babe64",
136
  "label": "",
137
  "source": "categorize:1",
138
  "target": "generate:casual",
139
  "markerEnd": {
140
  "type": "arrow"
141
+ },
142
+ "sourceHandle": "casual"
143
  },
144
  {
145
+ "id": "9debb81c-9b74-4e51-a6ae-a2f0188b781b",
146
  "label": "",
147
  "source": "categorize:1",
148
  "target": "generate:get_wechat",
149
  "markerEnd": {
150
  "type": "arrow"
151
+ },
152
+ "sourceHandle": "wechat"
153
  },
154
  {
155
+ "id": "95e183eb-d114-4ad4-946b-3fb2d3df340c",
156
  "label": "",
157
  "source": "categorize:1",
158
  "target": "generate:nowechat",
159
  "markerEnd": {
160
  "type": "arrow"
161
+ },
162
+ "sourceHandle": "giveup"
163
  },
164
  {
165
+ "id": "c59c1a4b-18ed-4a74-bbef-fa961a51d6a4",
166
  "label": "",
167
  "source": "retrieval:0",
168
  "target": "generate:aboutJob",
 
171
  }
172
  },
173
  {
174
+ "id": "aa902165-fe39-4cc4-8220-1abcf37b9f12",
175
  "label": "",
176
  "source": "relevant:0",
177
  "target": "generate:aboutJob",
 
190
  },
191
  "data": {
192
  "label": "Begin",
193
+ "form": {
194
  "prologue": "您好!我是AGI方向的猎头,了解到您是这方面的大佬,然后冒昧的就联系到您。这边有个机会想和您分享,RAGFlow正在招聘您这个岗位的资深的工程师不知道您那边是不是感兴趣?"
195
+ }
 
 
196
  },
197
  "sourcePosition": "left",
198
  "targetPosition": "right"
 
206
  },
207
  "data": {
208
  "label": "Answer",
209
+ "form": {}
 
 
210
  },
211
  "sourcePosition": "left",
212
  "targetPosition": "right"
 
220
  },
221
  "data": {
222
  "label": "Categorize",
223
+ "form": {
224
  "llm_id": "deepseek-chat",
225
  "category_description": {
226
  "about_job": {
 
244
  "to": "message:reject"
245
  }
246
  }
247
+ }
 
 
 
 
 
 
 
248
  },
249
  "sourcePosition": "left",
250
  "targetPosition": "right"
 
258
  },
259
  "data": {
260
  "label": "Message",
261
+ "form": {
262
  "messages": [
263
  "我简单介绍以下:\nRAGFlow 是一款基于深度文档理解构建的开源 RAG(Retrieval-Augmented Generation)引擎。RAGFlow 可以为各种规模的企业及个人提供一套精简的 RAG 工作流程,结合大语言模型(LLM)针对用户各类不同的复杂格式数据提供可靠的问答以及有理有据的引用。https://github.com/infiniflow/ragflow\n您那边还有什么要了解的?"
264
  ]
265
+ }
 
 
266
  },
267
  "sourcePosition": "left",
268
  "targetPosition": "right"
 
276
  },
277
  "data": {
278
  "label": "Answer",
279
+ "form": {}
 
 
 
 
 
 
 
 
280
  },
281
  "sourcePosition": "left",
282
  "targetPosition": "right"
 
290
  },
291
  "data": {
292
  "label": "Categorize",
293
+ "form": {
294
  "llm_id": "deepseek-chat",
295
  "category_description": {
296
  "about_job": {
 
315
  }
316
  },
317
  "message_history_window_size": 8
318
+ }
 
 
 
 
 
 
 
319
  },
320
  "sourcePosition": "left",
321
  "targetPosition": "right"
 
329
  },
330
  "data": {
331
  "label": "Generate",
332
+ "form": {
333
  "llm_id": "deepseek-chat",
334
  "prompt": "你是AGI方向的猎头,现在候选人的聊了和职位无关的话题,请耐心的回应候选人,并将话题往该AGI的职位上带,最好能要到候选人微信号以便后面保持联系。",
335
  "temperature": 0.9,
336
  "message_history_window_size": 12,
337
  "cite": false
338
+ }
 
 
339
  },
340
  "sourcePosition": "left",
341
  "targetPosition": "right"
 
349
  },
350
  "data": {
351
  "label": "Retrieval",
352
+ "form": {
353
  "similarity_threshold": 0.2,
354
  "keywords_similarity_weight": 0.3,
355
  "top_n": 6,
356
  "top_k": 1024,
357
  "rerank_id": "BAAI/bge-reranker-v2-m3",
358
  "kb_ids": ["869a236818b811ef91dffa163e197198"]
359
+ }
 
 
360
  },
361
  "sourcePosition": "left",
362
  "targetPosition": "right"
 
370
  },
371
  "data": {
372
  "label": "Generate",
373
+ "form": {
374
  "llm_id": "deepseek-chat",
375
  "prompt": "你是AGI方向的猎头,候选人问了有关职位或公司的问题,你根据以下职位信息回答。如果职位信息中不包含候选人的问题就回答不清楚、不知道、有待确认等。回答完后引导候选人加微信号,如:\n - 方便加一下微信吗,我把JD发您看看?\n - 微信号多少,我把详细职位JD发您?\n 职位信息如下:\n {input}\n 职位信息如上。",
376
  "temperature": 0.02
377
+ }
 
 
378
  },
379
  "sourcePosition": "left",
380
  "targetPosition": "right"
 
388
  },
389
  "data": {
390
  "label": "Generate",
391
+ "form": {
392
  "llm_id": "deepseek-chat",
393
  "prompt": "你是AGI方向的猎头,候选人表示不反感加微信,如果对方已经报了微信号,表示感谢和信任并表示马上会加上;如果没有,则问对方微信号多少。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
394
  "temperature": 0.1,
395
  "message_history_window_size": 12,
396
  "cite": false
397
+ }
 
 
398
  },
399
  "sourcePosition": "left",
400
  "targetPosition": "right"
 
408
  },
409
  "data": {
410
  "label": "Generate",
411
+ "form": {
412
  "llm_id": "deepseek-chat",
413
  "prompt": "你是AGI方向的猎头,当你提出加微信时对方表示拒绝。你需要耐心礼貌的回应候选人,表示对于保护隐私信息给予理解,也可以询问他对该职位的看法和顾虑。并在恰当的时机再次询问微信联系方式。也可以鼓励候选人主动与你取得联系。你的微信号是weixin_kevin,E-mail是kkk@ragflow.com。说话不要重复。不要总是您好。",
414
  "temperature": 0.1,
415
  "message_history_window_size": 12,
416
  "cite": false
417
+ }
 
 
418
  },
419
  "sourcePosition": "left",
420
  "targetPosition": "right"
 
428
  },
429
  "data": {
430
  "label": "Message",
431
+ "form": {
432
  "messages": [
433
  "好的,祝您生活愉快,工作顺利。",
434
  "哦,好的,感谢您宝贵的时间!"
435
  ]
436
+ }
 
 
437
  },
438
  "sourcePosition": "left",
439
  "targetPosition": "right"
web/src/pages/flow/utils.test.ts CHANGED
@@ -36,6 +36,8 @@ test('build nodes and edges from dsl', () => {
36
  const { edges, nodes } = buildNodesAndEdgesFromDSLComponents(
37
  headhunter_zh.components,
38
  );
 
 
39
  try {
40
  fs.writeFileSync(
41
  path.join(__dirname, 'headhunter_zh.json'),
 
36
  const { edges, nodes } = buildNodesAndEdgesFromDSLComponents(
37
  headhunter_zh.components,
38
  );
39
+ console.info('node length', nodes.length);
40
+ console.info('edge length', edges.length);
41
  try {
42
  fs.writeFileSync(
43
  path.join(__dirname, 'headhunter_zh.json'),
web/src/pages/flow/utils.ts CHANGED
@@ -6,19 +6,21 @@ import pipe from 'lodash/fp/pipe';
6
  import { Edge, MarkerType, Node, Position } from 'reactflow';
7
  import { v4 as uuidv4 } from 'uuid';
8
  import { NodeMap, Operator, initialFormValuesMap } from './constant';
9
- import { NodeData } from './interface';
10
 
11
  const buildEdges = (
12
  operatorIds: string[],
13
  currentId: string,
14
  allEdges: Edge[],
15
  isUpstream = false,
 
 
16
  ) => {
17
  operatorIds.forEach((cur) => {
18
  const source = isUpstream ? cur : currentId;
19
  const target = isUpstream ? currentId : cur;
20
  if (!allEdges.some((e) => e.source === source && e.target === target)) {
21
- allEdges.push({
22
  id: uuidv4(),
23
  label: '',
24
  // type: 'step',
@@ -27,7 +29,20 @@ const buildEdges = (
27
  markerEnd: {
28
  type: MarkerType.Arrow,
29
  },
30
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
  });
33
  };
@@ -39,22 +54,21 @@ export const buildNodesAndEdgesFromDSLComponents = (data: DSLComponents) => {
39
  Object.entries(data).forEach(([key, value]) => {
40
  const downstream = [...value.downstream];
41
  const upstream = [...value.upstream];
 
42
  nodes.push({
43
  id: key,
44
  type: NodeMap[value.obj.component_name as Operator] || 'ragNode',
45
  position: { x: 0, y: 0 },
46
  data: {
47
- label: value.obj.component_name,
48
- params: value.obj.params,
49
- downstream: downstream,
50
- upstream: upstream,
51
  },
52
  sourcePosition: Position.Left,
53
  targetPosition: Position.Right,
54
  });
55
 
56
- buildEdges(upstream, key, edges, true);
57
- buildEdges(downstream, key, edges, false);
58
  });
59
 
60
  return { nodes, edges };
 
6
  import { Edge, MarkerType, Node, Position } from 'reactflow';
7
  import { v4 as uuidv4 } from 'uuid';
8
  import { NodeMap, Operator, initialFormValuesMap } from './constant';
9
+ import { ICategorizeItemResult, NodeData } from './interface';
10
 
11
  const buildEdges = (
12
  operatorIds: string[],
13
  currentId: string,
14
  allEdges: Edge[],
15
  isUpstream = false,
16
+ componentName: string,
17
+ nodeParams: Record<string, unknown>,
18
  ) => {
19
  operatorIds.forEach((cur) => {
20
  const source = isUpstream ? cur : currentId;
21
  const target = isUpstream ? currentId : cur;
22
  if (!allEdges.some((e) => e.source === source && e.target === target)) {
23
+ const edge: Edge = {
24
  id: uuidv4(),
25
  label: '',
26
  // type: 'step',
 
29
  markerEnd: {
30
  type: MarkerType.Arrow,
31
  },
32
+ };
33
+ if (componentName === Operator.Categorize && !isUpstream) {
34
+ const categoryDescription =
35
+ nodeParams.category_description as ICategorizeItemResult;
36
+
37
+ const name = Object.keys(categoryDescription).find(
38
+ (x) => categoryDescription[x].to === target,
39
+ );
40
+
41
+ if (name) {
42
+ edge.sourceHandle = name;
43
+ }
44
+ }
45
+ allEdges.push(edge);
46
  }
47
  });
48
  };
 
54
  Object.entries(data).forEach(([key, value]) => {
55
  const downstream = [...value.downstream];
56
  const upstream = [...value.upstream];
57
+ const { component_name: componentName, params } = value.obj;
58
  nodes.push({
59
  id: key,
60
  type: NodeMap[value.obj.component_name as Operator] || 'ragNode',
61
  position: { x: 0, y: 0 },
62
  data: {
63
+ label: componentName,
64
+ form: params,
 
 
65
  },
66
  sourcePosition: Position.Left,
67
  targetPosition: Position.Right,
68
  });
69
 
70
+ buildEdges(upstream, key, edges, true, componentName, params);
71
+ buildEdges(downstream, key, edges, false, componentName, params);
72
  });
73
 
74
  return { nodes, edges };