Kevin Hu commited on
Commit
a4f36a5
·
1 Parent(s): 2bdad3e

Add iteration for agent. (#4258)

Browse files

### What problem does this PR solve?

#4242
### Type of change

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

agent/canvas.py CHANGED
@@ -18,6 +18,9 @@ import json
18
  from abc import ABC
19
  from copy import deepcopy
20
  from functools import partial
 
 
 
21
  from agent.component import component_class
22
  from agent.component.base import ComponentBase
23
 
@@ -83,7 +86,8 @@ class Canvas(ABC):
83
  }
84
  },
85
  "downstream": [],
86
- "upstream": []
 
87
  }
88
  },
89
  "history": [],
@@ -207,6 +211,14 @@ class Canvas(ABC):
207
  waiting.append(c)
208
  continue
209
  yield "*'{}'* is running...🕞".format(self.get_compnent_name(c))
 
 
 
 
 
 
 
 
210
  try:
211
  ans = cpn.run(self.history, **kwargs)
212
  except Exception as e:
@@ -215,16 +227,26 @@ class Canvas(ABC):
215
  ran += 1
216
  raise e
217
  self.path[-1].append(c)
 
218
  ran += 1
219
 
220
- for m in prepare2run(self.components[self.path[-2][-1]]["downstream"]):
 
 
 
 
 
 
 
 
 
221
  yield {"content": m, "running_status": True}
222
 
223
  while 0 <= ran < len(self.path[-1]):
224
  logging.debug(f"Canvas.run: {ran} {self.path}")
225
  cpn_id = self.path[-1][ran]
226
  cpn = self.get_component(cpn_id)
227
- if not cpn["downstream"]:
228
  break
229
 
230
  loop = self._find_loop()
@@ -239,7 +261,15 @@ class Canvas(ABC):
239
  yield {"content": m, "running_status": True}
240
  continue
241
 
242
- for m in prepare2run(cpn["downstream"]):
 
 
 
 
 
 
 
 
243
  yield {"content": m, "running_status": True}
244
 
245
  if ran >= len(self.path[-1]) and waiting:
@@ -247,6 +277,7 @@ class Canvas(ABC):
247
  waiting = []
248
  for m in prepare2run(without_dependent_checking):
249
  yield {"content": m, "running_status": True}
 
250
  ran -= 1
251
 
252
  if self.answer:
@@ -294,7 +325,7 @@ class Canvas(ABC):
294
  return False
295
 
296
  for i in range(len(path)):
297
- if path[i].lower().find("answer") >= 0:
298
  path = path[:i]
299
  break
300
 
 
18
  from abc import ABC
19
  from copy import deepcopy
20
  from functools import partial
21
+
22
+ import pandas as pd
23
+
24
  from agent.component import component_class
25
  from agent.component.base import ComponentBase
26
 
 
86
  }
87
  },
88
  "downstream": [],
89
+ "upstream": [],
90
+ "parent_id": ""
91
  }
92
  },
93
  "history": [],
 
211
  waiting.append(c)
212
  continue
213
  yield "*'{}'* is running...🕞".format(self.get_compnent_name(c))
214
+
215
+ if cpn.component_name.lower() == "iteration":
216
+ st_cpn = cpn.get_start()
217
+ assert st_cpn, "Start component not found for Iteration."
218
+ if not st_cpn["obj"].end():
219
+ cpn = st_cpn["obj"]
220
+ c = cpn._id
221
+
222
  try:
223
  ans = cpn.run(self.history, **kwargs)
224
  except Exception as e:
 
227
  ran += 1
228
  raise e
229
  self.path[-1].append(c)
230
+
231
  ran += 1
232
 
233
+ downstream = self.components[self.path[-2][-1]]["downstream"]
234
+ if not downstream and self.components[self.path[-2][-1]].get("parent_id"):
235
+ cid = self.path[-2][-1]
236
+ pid = self.components[cid]["parent_id"]
237
+ o, _ = self.components[cid]["obj"].output(allow_partial=False)
238
+ oo, _ = self.components[pid]["obj"].output(allow_partial=False)
239
+ self.components[pid]["obj"].set(pd.concat([oo, o], ignore_index=True))
240
+ downstream = [pid]
241
+
242
+ for m in prepare2run(downstream):
243
  yield {"content": m, "running_status": True}
244
 
245
  while 0 <= ran < len(self.path[-1]):
246
  logging.debug(f"Canvas.run: {ran} {self.path}")
247
  cpn_id = self.path[-1][ran]
248
  cpn = self.get_component(cpn_id)
249
+ if not any([cpn["downstream"], cpn.get("parent_id"), waiting]):
250
  break
251
 
252
  loop = self._find_loop()
 
261
  yield {"content": m, "running_status": True}
262
  continue
263
 
264
+ downstream = cpn["downstream"]
265
+ if not downstream and cpn.get("parent_id"):
266
+ pid = cpn["parent_id"]
267
+ _, o = cpn["obj"].output(allow_partial=False)
268
+ _, oo = self.components[pid]["obj"].output(allow_partial=False)
269
+ self.components[pid]["obj"].set_output(pd.concat([oo.dropna(axis=1), o.dropna(axis=1)], ignore_index=True))
270
+ downstream = [pid]
271
+
272
+ for m in prepare2run(downstream):
273
  yield {"content": m, "running_status": True}
274
 
275
  if ran >= len(self.path[-1]) and waiting:
 
277
  waiting = []
278
  for m in prepare2run(without_dependent_checking):
279
  yield {"content": m, "running_status": True}
280
+ without_dependent_checking = []
281
  ran -= 1
282
 
283
  if self.answer:
 
325
  return False
326
 
327
  for i in range(len(path)):
328
+ if path[i].lower().find("answer") == 0 or path[i].lower().find("iterationitem") == 0:
329
  path = path[:i]
330
  break
331
 
agent/component/__init__.py CHANGED
@@ -32,6 +32,8 @@ from .crawler import Crawler, CrawlerParam
32
  from .invoke import Invoke, InvokeParam
33
  from .template import Template, TemplateParam
34
  from .email import Email, EmailParam
 
 
35
 
36
 
37
 
@@ -103,6 +105,10 @@ __all__ = [
103
  "CrawlerParam",
104
  "Invoke",
105
  "InvokeParam",
 
 
 
 
106
  "Template",
107
  "TemplateParam",
108
  "Email",
 
32
  from .invoke import Invoke, InvokeParam
33
  from .template import Template, TemplateParam
34
  from .email import Email, EmailParam
35
+ from .iteration import Iteration, IterationParam
36
+ from .iterationitem import IterationItem, IterationItemParam
37
 
38
 
39
 
 
105
  "CrawlerParam",
106
  "Invoke",
107
  "InvokeParam",
108
+ "Iteration",
109
+ "IterationParam",
110
+ "IterationItem",
111
+ "IterationItemParam",
112
  "Template",
113
  "TemplateParam",
114
  "Email",
agent/component/baidu.py CHANGED
@@ -44,7 +44,7 @@ class Baidu(ComponentBase, ABC):
44
  return Baidu.be_output("")
45
 
46
  try:
47
- url = 'https://www.baidu.com/s?wd=' + ans + '&rn=' + str(self._param.top_n)
48
  headers = {
49
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'}
50
  response = requests.get(url=url, headers=headers)
 
44
  return Baidu.be_output("")
45
 
46
  try:
47
+ url = 'http://www.baidu.com/s?wd=' + ans + '&rn=' + str(self._param.top_n)
48
  headers = {
49
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'}
50
  response = requests.get(url=url, headers=headers)
agent/component/base.py CHANGED
@@ -426,10 +426,14 @@ class ComponentBase(ABC):
426
 
427
  def output(self, allow_partial=True) -> Tuple[str, Union[pd.DataFrame, partial]]:
428
  o = getattr(self._param, self._param.output_var_name)
429
- if not isinstance(o, partial) and not isinstance(o, pd.DataFrame):
430
- if not isinstance(o, list):
431
- o = [o]
432
- o = pd.DataFrame(o)
 
 
 
 
433
 
434
  if allow_partial or not isinstance(o, partial):
435
  if not isinstance(o, partial) and not isinstance(o, pd.DataFrame):
@@ -574,4 +578,8 @@ class ComponentBase(ABC):
574
  return self._canvas.get_component(cpn_id)["obj"].component_name.lower()
575
 
576
  def debug(self, **kwargs):
577
- return self._run([], **kwargs)
 
 
 
 
 
426
 
427
  def output(self, allow_partial=True) -> Tuple[str, Union[pd.DataFrame, partial]]:
428
  o = getattr(self._param, self._param.output_var_name)
429
+ if not isinstance(o, partial):
430
+ if not isinstance(o, pd.DataFrame):
431
+ if isinstance(o, list):
432
+ return self._param.output_var_name, pd.DataFrame(o)
433
+ if o is None:
434
+ return self._param.output_var_name, pd.DataFrame()
435
+ return self._param.output_var_name, pd.DataFrame([{"content": str(o)}])
436
+ return self._param.output_var_name, o
437
 
438
  if allow_partial or not isinstance(o, partial):
439
  if not isinstance(o, partial) and not isinstance(o, pd.DataFrame):
 
578
  return self._canvas.get_component(cpn_id)["obj"].component_name.lower()
579
 
580
  def debug(self, **kwargs):
581
+ return self._run([], **kwargs)
582
+
583
+ def get_parent(self):
584
+ pid = self._canvas.get_component(self._id)["parent_id"]
585
+ return self._canvas.get_component(pid)["obj"]
agent/component/iteration.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ from abc import ABC
17
+ from agent.component.base import ComponentBase, ComponentParamBase
18
+
19
+
20
+ class IterationParam(ComponentParamBase):
21
+ """
22
+ Define the Iteration component parameters.
23
+ """
24
+
25
+ def __init__(self):
26
+ super().__init__()
27
+ self.delimiter = ","
28
+
29
+ def check(self):
30
+ self.check_empty(self.delimiter, "Delimiter")
31
+
32
+
33
+ class Iteration(ComponentBase, ABC):
34
+ component_name = "Iteration"
35
+
36
+ def get_start(self):
37
+ for cid in self._canvas.components.keys():
38
+ if self._canvas.get_component(cid)["obj"].component_name.lower() != "iterationitem":
39
+ continue
40
+ if self._canvas.get_component(cid)["parent_id"] == self._id:
41
+ return self._canvas.get_component(cid)
42
+
43
+ def _run(self, history, **kwargs):
44
+ return self.output(allow_partial=False)[1]
45
+
agent/component/iterationitem.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ from abc import ABC
17
+ import pandas as pd
18
+ from agent.component.base import ComponentBase, ComponentParamBase
19
+
20
+
21
+ class IterationItemParam(ComponentParamBase):
22
+ """
23
+ Define the IterationItem component parameters.
24
+ """
25
+ def check(self):
26
+ return True
27
+
28
+
29
+ class IterationItem(ComponentBase, ABC):
30
+ component_name = "IterationItem"
31
+
32
+ def __init__(self, canvas, id, param: ComponentParamBase):
33
+ super().__init__(canvas, id, param)
34
+ self._idx = 0
35
+
36
+ def _run(self, history, **kwargs):
37
+ parent = self.get_parent()
38
+ ans = parent.get_input()
39
+ ans = parent._param.delimiter.join(ans["content"]) if "content" in ans else ""
40
+ ans = [a.strip() for a in ans.split(parent._param.delimiter)]
41
+ df = pd.DataFrame([{"content": ans[self._idx]}])
42
+ self._idx += 1
43
+ if self._idx >= len(ans):
44
+ self._idx = -1
45
+ return df
46
+
47
+ def end(self):
48
+ return self._idx == -1
49
+
api/db/services/api_service.py CHANGED
@@ -53,7 +53,6 @@ class API4ConversationService(CommonService):
53
  sessions = sessions.order_by(cls.model.getter_by(orderby).desc())
54
  else:
55
  sessions = sessions.order_by(cls.model.getter_by(orderby).asc())
56
- sessions = sessions.where(cls.model.user_id == tenant_id)
57
  sessions = sessions.paginate(page_number, items_per_page)
58
 
59
  return list(sessions.dicts())
 
53
  sessions = sessions.order_by(cls.model.getter_by(orderby).desc())
54
  else:
55
  sessions = sessions.order_by(cls.model.getter_by(orderby).asc())
 
56
  sessions = sessions.paginate(page_number, items_per_page)
57
 
58
  return list(sessions.dicts())