Browse Source

Add iteration for agent. (#4258)

### What problem does this PR solve?

#4242
### Type of change

- [x] New Feature (non-breaking change which adds functionality)
tags/nightly
Kevin Hu 10 months ago
parent
commit
c3e3f0fbb4
No account linked to committer's email address

+ 36
- 5
agent/canvas.py View File

from abc import ABC from abc import ABC
from copy import deepcopy from copy import deepcopy
from functools import partial from functools import partial

import pandas as pd

from agent.component import component_class from agent.component import component_class
from agent.component.base import ComponentBase from agent.component.base import ComponentBase


} }
}, },
"downstream": [], "downstream": [],
"upstream": []
"upstream": [],
"parent_id": ""
} }
}, },
"history": [], "history": [],
waiting.append(c) waiting.append(c)
continue continue
yield "*'{}'* is running...🕞".format(self.get_compnent_name(c)) yield "*'{}'* is running...🕞".format(self.get_compnent_name(c))

if cpn.component_name.lower() == "iteration":
st_cpn = cpn.get_start()
assert st_cpn, "Start component not found for Iteration."
if not st_cpn["obj"].end():
cpn = st_cpn["obj"]
c = cpn._id

try: try:
ans = cpn.run(self.history, **kwargs) ans = cpn.run(self.history, **kwargs)
except Exception as e: except Exception as e:
ran += 1 ran += 1
raise e raise e
self.path[-1].append(c) self.path[-1].append(c)

ran += 1 ran += 1


for m in prepare2run(self.components[self.path[-2][-1]]["downstream"]):
downstream = self.components[self.path[-2][-1]]["downstream"]
if not downstream and self.components[self.path[-2][-1]].get("parent_id"):
cid = self.path[-2][-1]
pid = self.components[cid]["parent_id"]
o, _ = self.components[cid]["obj"].output(allow_partial=False)
oo, _ = self.components[pid]["obj"].output(allow_partial=False)
self.components[pid]["obj"].set(pd.concat([oo, o], ignore_index=True))
downstream = [pid]

for m in prepare2run(downstream):
yield {"content": m, "running_status": True} yield {"content": m, "running_status": True}


while 0 <= ran < len(self.path[-1]): while 0 <= ran < len(self.path[-1]):
logging.debug(f"Canvas.run: {ran} {self.path}") logging.debug(f"Canvas.run: {ran} {self.path}")
cpn_id = self.path[-1][ran] cpn_id = self.path[-1][ran]
cpn = self.get_component(cpn_id) cpn = self.get_component(cpn_id)
if not cpn["downstream"]:
if not any([cpn["downstream"], cpn.get("parent_id"), waiting]):
break break


loop = self._find_loop() loop = self._find_loop()
yield {"content": m, "running_status": True} yield {"content": m, "running_status": True}
continue continue


for m in prepare2run(cpn["downstream"]):
downstream = cpn["downstream"]
if not downstream and cpn.get("parent_id"):
pid = cpn["parent_id"]
_, o = cpn["obj"].output(allow_partial=False)
_, oo = self.components[pid]["obj"].output(allow_partial=False)
self.components[pid]["obj"].set_output(pd.concat([oo.dropna(axis=1), o.dropna(axis=1)], ignore_index=True))
downstream = [pid]

for m in prepare2run(downstream):
yield {"content": m, "running_status": True} yield {"content": m, "running_status": True}


if ran >= len(self.path[-1]) and waiting: if ran >= len(self.path[-1]) and waiting:
waiting = [] waiting = []
for m in prepare2run(without_dependent_checking): for m in prepare2run(without_dependent_checking):
yield {"content": m, "running_status": True} yield {"content": m, "running_status": True}
without_dependent_checking = []
ran -= 1 ran -= 1


if self.answer: if self.answer:
return False return False


for i in range(len(path)): for i in range(len(path)):
if path[i].lower().find("answer") >= 0:
if path[i].lower().find("answer") == 0 or path[i].lower().find("iterationitem") == 0:
path = path[:i] path = path[:i]
break break



+ 6
- 0
agent/component/__init__.py View File

from .invoke import Invoke, InvokeParam from .invoke import Invoke, InvokeParam
from .template import Template, TemplateParam from .template import Template, TemplateParam
from .email import Email, EmailParam from .email import Email, EmailParam
from .iteration import Iteration, IterationParam
from .iterationitem import IterationItem, IterationItemParam






"CrawlerParam", "CrawlerParam",
"Invoke", "Invoke",
"InvokeParam", "InvokeParam",
"Iteration",
"IterationParam",
"IterationItem",
"IterationItemParam",
"Template", "Template",
"TemplateParam", "TemplateParam",
"Email", "Email",

+ 1
- 1
agent/component/baidu.py View File

return Baidu.be_output("") return Baidu.be_output("")


try: try:
url = 'https://www.baidu.com/s?wd=' + ans + '&rn=' + str(self._param.top_n)
url = 'http://www.baidu.com/s?wd=' + ans + '&rn=' + str(self._param.top_n)
headers = { headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'} 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'}
response = requests.get(url=url, headers=headers) response = requests.get(url=url, headers=headers)

+ 13
- 5
agent/component/base.py View File



def output(self, allow_partial=True) -> Tuple[str, Union[pd.DataFrame, partial]]: def output(self, allow_partial=True) -> Tuple[str, Union[pd.DataFrame, partial]]:
o = getattr(self._param, self._param.output_var_name) o = getattr(self._param, self._param.output_var_name)
if not isinstance(o, partial) and not isinstance(o, pd.DataFrame):
if not isinstance(o, list):
o = [o]
o = pd.DataFrame(o)
if not isinstance(o, partial):
if not isinstance(o, pd.DataFrame):
if isinstance(o, list):
return self._param.output_var_name, pd.DataFrame(o)
if o is None:
return self._param.output_var_name, pd.DataFrame()
return self._param.output_var_name, pd.DataFrame([{"content": str(o)}])
return self._param.output_var_name, o


if allow_partial or not isinstance(o, partial): if allow_partial or not isinstance(o, partial):
if not isinstance(o, partial) and not isinstance(o, pd.DataFrame): if not isinstance(o, partial) and not isinstance(o, pd.DataFrame):
return self._canvas.get_component(cpn_id)["obj"].component_name.lower() return self._canvas.get_component(cpn_id)["obj"].component_name.lower()


def debug(self, **kwargs): def debug(self, **kwargs):
return self._run([], **kwargs)
return self._run([], **kwargs)

def get_parent(self):
pid = self._canvas.get_component(self._id)["parent_id"]
return self._canvas.get_component(pid)["obj"]

+ 45
- 0
agent/component/iteration.py View File

#
# Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from abc import ABC
from agent.component.base import ComponentBase, ComponentParamBase


class IterationParam(ComponentParamBase):
"""
Define the Iteration component parameters.
"""

def __init__(self):
super().__init__()
self.delimiter = ","

def check(self):
self.check_empty(self.delimiter, "Delimiter")


class Iteration(ComponentBase, ABC):
component_name = "Iteration"

def get_start(self):
for cid in self._canvas.components.keys():
if self._canvas.get_component(cid)["obj"].component_name.lower() != "iterationitem":
continue
if self._canvas.get_component(cid)["parent_id"] == self._id:
return self._canvas.get_component(cid)

def _run(self, history, **kwargs):
return self.output(allow_partial=False)[1]


+ 49
- 0
agent/component/iterationitem.py View File

#
# Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from abc import ABC
import pandas as pd
from agent.component.base import ComponentBase, ComponentParamBase


class IterationItemParam(ComponentParamBase):
"""
Define the IterationItem component parameters.
"""
def check(self):
return True


class IterationItem(ComponentBase, ABC):
component_name = "IterationItem"

def __init__(self, canvas, id, param: ComponentParamBase):
super().__init__(canvas, id, param)
self._idx = 0

def _run(self, history, **kwargs):
parent = self.get_parent()
ans = parent.get_input()
ans = parent._param.delimiter.join(ans["content"]) if "content" in ans else ""
ans = [a.strip() for a in ans.split(parent._param.delimiter)]
df = pd.DataFrame([{"content": ans[self._idx]}])
self._idx += 1
if self._idx >= len(ans):
self._idx = -1
return df

def end(self):
return self._idx == -1


+ 0
- 1
api/db/services/api_service.py View File

sessions = sessions.order_by(cls.model.getter_by(orderby).desc()) sessions = sessions.order_by(cls.model.getter_by(orderby).desc())
else: else:
sessions = sessions.order_by(cls.model.getter_by(orderby).asc()) sessions = sessions.order_by(cls.model.getter_by(orderby).asc())
sessions = sessions.where(cls.model.user_id == tenant_id)
sessions = sessions.paginate(page_number, items_per_page) sessions = sessions.paginate(page_number, items_per_page)


return list(sessions.dicts()) return list(sessions.dicts())

Loading…
Cancel
Save