From ef2f745ff5499f93aa260462883d7a0250b89273 Mon Sep 17 00:00:00 2001 From: Kye Date: Fri, 17 Nov 2023 20:04:15 -0800 Subject: [PATCH 1/8] no griptape, no artifacts, cleanup --- mkdocs.yml | 6 +- pyproject.toml | 1 - requirements.txt | 1 - sequential_workflow_example.py | 6 +- swarms/__init__.py | 2 +- swarms/artifacts/__init__.py | 0 swarms/artifacts/base.py | 81 -------- swarms/artifacts/error_artifact.py | 19 -- swarms/artifacts/main.py | 74 ------- swarms/models/simple_ada.py | 1 + swarms/structs/__init__.py | 6 +- swarms/structs/task.py | 320 ++++++++++++++--------------- swarms/structs/workflow.py | 161 +++++++-------- swarms/swarms/autoscaler.py | 4 +- 14 files changed, 253 insertions(+), 429 deletions(-) delete mode 100644 swarms/artifacts/__init__.py delete mode 100644 swarms/artifacts/base.py delete mode 100644 swarms/artifacts/error_artifact.py delete mode 100644 swarms/artifacts/main.py diff --git a/mkdocs.yml b/mkdocs.yml index 7b331f02..f33c71dc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -104,9 +104,9 @@ nav: - swarms.memory: - PineconeVectorStoreStore: "swarms/memory/pinecone.md" - PGVectorStore: "swarms/memory/pg.md" - - swarms.chunkers: - - BaseChunker: "swarms/chunkers/basechunker.md" - - PdfChunker: "swarms/chunkers/pdf_chunker.md" + # - swarms.chunkers: + # - BaseChunker: "swarms/chunkers/basechunker.md" + # - PdfChunker: "swarms/chunkers/pdf_chunker.md" - Guides: - Overview: "examples/index.md" - Agents: diff --git a/pyproject.toml b/pyproject.toml index 2c521530..04bdfe2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ diffusers = "*" accelerate = "*" sentencepiece = "*" wget = "*" -griptape = "*" httpx = "*" tiktoken = "*" safetensors = "*" diff --git a/requirements.txt b/requirements.txt index 6d542159..8dad8dc6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -33,7 +33,6 @@ chromadb tiktoken tabulate colored -griptape addict backoff ratelimit diff --git a/sequential_workflow_example.py b/sequential_workflow_example.py index 9c17a072..76c17ab2 100644 --- a/sequential_workflow_example.py +++ b/sequential_workflow_example.py @@ -4,9 +4,7 @@ from swarms.structs.sequential_workflow import SequentialWorkflow # Example usage -api_key = ( - "" # Your actual API key here -) +api_key = "" # Your actual API key here # Initialize the language flow llm = OpenAIChat( @@ -47,4 +45,4 @@ workflow.run() # Output the results for task in workflow.tasks: - print(f"Task: {task.description}, Result: {task.result}") \ No newline at end of file + print(f"Task: {task.description}, Result: {task.result}") diff --git a/swarms/__init__.py b/swarms/__init__.py index 338cc8f9..0fd05d72 100644 --- a/swarms/__init__.py +++ b/swarms/__init__.py @@ -8,4 +8,4 @@ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" from swarms.agents import * # noqa: E402, F403 from swarms.swarms import * # noqa: E402, F403 from swarms.structs import * # noqa: E402, F403 -from swarms.models import * # noqa: E402, F403 \ No newline at end of file +from swarms.models import * # noqa: E402, F403 diff --git a/swarms/artifacts/__init__.py b/swarms/artifacts/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/swarms/artifacts/base.py b/swarms/artifacts/base.py deleted file mode 100644 index dac7a523..00000000 --- a/swarms/artifacts/base.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations -import json -import uuid -from abc import ABC, abstractmethod -from attr import define, field, Factory -from marshmallow import class_registry -from marshmallow.exceptions import RegistryError - - -@define -class BaseArtifact(ABC): - id: str = field(default=Factory(lambda: uuid.uuid4().hex), kw_only=True) - name: str = field( - default=Factory(lambda self: self.id, takes_self=True), kw_only=True - ) - value: any = field() - type: str = field( - default=Factory(lambda self: self.__class__.__name__, takes_self=True), - kw_only=True, - ) - - @classmethod - def value_to_bytes(cls, value: any) -> bytes: - if isinstance(value, bytes): - return value - else: - return str(value).encode() - - @classmethod - def value_to_dict(cls, value: any) -> dict: - if isinstance(value, dict): - dict_value = value - else: - dict_value = json.loads(value) - - return {k: v for k, v in dict_value.items()} - - @classmethod - def from_dict(cls, artifact_dict: dict) -> BaseArtifact: - from griptape.schemas import ( - TextArtifactSchema, - InfoArtifactSchema, - ErrorArtifactSchema, - BlobArtifactSchema, - CsvRowArtifactSchema, - ListArtifactSchema, - ) - - class_registry.register("TextArtifact", TextArtifactSchema) - class_registry.register("InfoArtifact", InfoArtifactSchema) - class_registry.register("ErrorArtifact", ErrorArtifactSchema) - class_registry.register("BlobArtifact", BlobArtifactSchema) - class_registry.register("CsvRowArtifact", CsvRowArtifactSchema) - class_registry.register("ListArtifact", ListArtifactSchema) - - try: - return class_registry.get_class(artifact_dict["type"])().load(artifact_dict) - except RegistryError: - raise ValueError("Unsupported artifact type") - - @classmethod - def from_json(cls, artifact_str: str) -> BaseArtifact: - return cls.from_dict(json.loads(artifact_str)) - - def __str__(self): - return json.dumps(self.to_dict()) - - def to_json(self) -> str: - return json.dumps(self.to_dict()) - - @abstractmethod - def to_text(self) -> str: - ... - - @abstractmethod - def to_dict(self) -> dict: - ... - - @abstractmethod - def __add__(self, other: BaseArtifact) -> BaseArtifact: - ... diff --git a/swarms/artifacts/error_artifact.py b/swarms/artifacts/error_artifact.py deleted file mode 100644 index 0bee1aa9..00000000 --- a/swarms/artifacts/error_artifact.py +++ /dev/null @@ -1,19 +0,0 @@ -from __future__ import annotations -from attr import define, field -from swarms.artifacts.base import BaseArtifact - - -@define(frozen=True) -class ErrorArtifact(BaseArtifact): - value: str = field(converter=str) - - def __add__(self, other: ErrorArtifact) -> ErrorArtifact: - return ErrorArtifact(self.value + other.value) - - def to_text(self) -> str: - return self.value - - def to_dict(self) -> dict: - from griptape.schemas import ErrorArtifactSchema - - return dict(ErrorArtifactSchema().dump(self)) diff --git a/swarms/artifacts/main.py b/swarms/artifacts/main.py deleted file mode 100644 index 075cd34d..00000000 --- a/swarms/artifacts/main.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import annotations -import pprint -import json - -from typing import Optional -from pydantic import BaseModel, Field, StrictStr - - -class Artifact(BaseModel): - """ - - Artifact that has the task has been produced - - Attributes: - ----------- - - artifact_id: str - ID of the artifact - - file_name: str - Filename of the artifact - - relative_path: str - Relative path of the artifact - - - """ - - artifact_id: StrictStr = Field(..., description="ID of the artifact") - file_name: StrictStr = Field(..., description="Filename of the artifact") - relative_path: Optional[StrictStr] = Field( - None, description="Relative path of the artifact" - ) - __properties = ["artifact_id", "file_name", "relative_path"] - - class Config: - """Pydantic configuration""" - - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.dict(by_alias=True)) - - @classmethod - def from_json(cls, json_str: str) -> Artifact: - """Create an instance of Artifact from a json string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self): - """Returns the dict representation of the model""" - _dict = self.dict(by_alias=True, exclude={}, exclude_none=True) - return _dict - - @classmethod - def from_dict(cls, obj: dict) -> Artifact: - """Create an instance of Artifact from a dict""" - - if obj is None: - return None - - if not isinstance(obj, dict): - return Artifact.parse_obj(obj) - - _obj = Artifact.parse_obj( - { - "artifact_id": obj.get("artifact_id"), - "file_name": obj.get("file_name"), - "relative_path": obj.get("relative_path"), - } - ) - - return _obj diff --git a/swarms/models/simple_ada.py b/swarms/models/simple_ada.py index 6a0dbcc9..3662dda2 100644 --- a/swarms/models/simple_ada.py +++ b/swarms/models/simple_ada.py @@ -1,3 +1,4 @@ +import os from openai import OpenAI client = OpenAI() diff --git a/swarms/structs/__init__.py b/swarms/structs/__init__.py index a842359c..1c66de94 100644 --- a/swarms/structs/__init__.py +++ b/swarms/structs/__init__.py @@ -1,6 +1,6 @@ -from swarms.structs.workflow import Workflow -from swarms.structs.task import Task +# from swarms.structs.workflow import Workflow +# from swarms.structs.task import Task from swarms.structs.flow import Flow from swarms.structs.sequential_workflow import SequentialWorkflow -__all__ = ["Workflow", "Task", "Flow", "SequentialWorkflow"] +__all__ = ["Flow", "SequentialWorkflow"] diff --git a/swarms/structs/task.py b/swarms/structs/task.py index 80f95d4d..3d479c43 100644 --- a/swarms/structs/task.py +++ b/swarms/structs/task.py @@ -1,174 +1,174 @@ -from __future__ import annotations +# from __future__ import annotations -import json -import pprint -import uuid -from abc import ABC, abstractmethod -from enum import Enum -from typing import Any, List, Optional, Union +# import json +# import pprint +# import uuid +# from abc import ABC, abstractmethod +# from enum import Enum +# from typing import Any, List, Optional, Union -from pydantic import BaseModel, Field, StrictStr -from swarms.artifacts.main import Artifact -from swarms.artifacts.error_artifact import ErrorArtifact +# from pydantic import BaseModel, Field, StrictStr +# # from swarms.artifacts.main import Artifact +# # from swarms.artifacts.error_artifact import ErrorArtifact -class BaseTask(ABC): - class State(Enum): - PENDING = 1 - EXECUTING = 2 - FINISHED = 3 +# class BaseTask(ABC): +# class State(Enum): +# PENDING = 1 +# EXECUTING = 2 +# FINISHED = 3 - def __init__(self): - self.id: str = uuid.uuid4().hex - self.state: BaseTask.State = self.State.PENDING - self.parent_ids: List[str] = [] - self.child_ids: List[str] = [] - self.output: Optional[Union[Artifact, ErrorArtifact]] = None - self.structure = None +# def __init__(self): +# self.id: str = uuid.uuid4().hex +# self.state: BaseTask.State = self.State.PENDING +# self.parent_ids: List[str] = [] +# self.child_ids: List[str] = [] +# self.output = None +# self.structure = None - @property - @abstractmethod - def input(self) -> Any: - pass +# @property +# @abstractmethod +# def input(self) -> Any: +# pass - @property - def parents(self) -> List[BaseTask]: - return [self.structure.find_task(parent_id) for parent_id in self.parent_ids] +# @property +# def parents(self) -> List[BaseTask]: +# return [self.structure.find_task(parent_id) for parent_id in self.parent_ids] - @property - def children(self) -> List[BaseTask]: - return [self.structure.find_task(child_id) for child_id in self.child_ids] +# @property +# def children(self) -> List[BaseTask]: +# return [self.structure.find_task(child_id) for child_id in self.child_ids] - def __rshift__(self, child: BaseTask) -> BaseTask: - return self.add_child(child) +# def __rshift__(self, child: BaseTask) -> BaseTask: +# return self.add_child(child) - def __lshift__(self, child: BaseTask) -> BaseTask: - return self.add_parent(child) +# def __lshift__(self, child: BaseTask) -> BaseTask: +# return self.add_parent(child) - def preprocess(self, structure) -> BaseTask: - self.structure = structure - return self +# def preprocess(self, structure) -> BaseTask: +# self.structure = structure +# return self - def add_child(self, child: BaseTask) -> BaseTask: - if self.structure: - child.structure = self.structure - elif child.structure: - self.structure = child.structure +# def add_child(self, child: BaseTask) -> BaseTask: +# if self.structure: +# child.structure = self.structure +# elif child.structure: +# self.structure = child.structure - if child not in self.structure.tasks: - self.structure.tasks.append(child) - - if self not in self.structure.tasks: - self.structure.tasks.append(self) +# if child not in self.structure.tasks: +# self.structure.tasks.append(child) + +# if self not in self.structure.tasks: +# self.structure.tasks.append(self) - if child.id not in self.child_ids: - self.child_ids.append(child.id) - - if self.id not in child.parent_ids: - child.parent_ids.append(self.id) - - return child - - def add_parent(self, parent: BaseTask) -> BaseTask: - if self.structure: - parent.structure = self.structure - elif parent.structure: - self.structure = parent.structure - - if parent not in self.structure.tasks: - self.structure.tasks.append(parent) - - if self not in self.structure.tasks: - self.structure.tasks.append(self) - - if parent.id not in self.parent_ids: - self.parent_ids.append(parent.id) - - if self.id not in parent.child_ids: - parent.child_ids.append(self.id) - - return parent - - def is_pending(self) -> bool: - return self.state == self.State.PENDING - - def is_finished(self) -> bool: - return self.state == self.State.FINISHED - - def is_executing(self) -> bool: - return self.state == self.State.EXECUTING - - def before_run(self) -> None: - pass - - def after_run(self) -> None: - pass - - def execute(self) -> Optional[Union[Artifact, ErrorArtifact]]: - try: - self.state = self.State.EXECUTING - self.before_run() - self.output = self.run() - self.after_run() - except Exception as e: - self.output = ErrorArtifact(str(e)) - finally: - self.state = self.State.FINISHED - return self.output - - def can_execute(self) -> bool: - return self.state == self.State.PENDING and all( - parent.is_finished() for parent in self.parents - ) - - def reset(self) -> BaseTask: - self.state = self.State.PENDING - self.output = None - return self - - @abstractmethod - def run(self) -> Optional[Union[Artifact, ErrorArtifact]]: - pass - - -class Task(BaseModel): - input: Optional[StrictStr] = Field(None, description="Input prompt for the task") - additional_input: Optional[Any] = Field( - None, description="Input parameters for the task. Any value is allowed" - ) - task_id: StrictStr = Field(..., description="ID of the task") - - class Config: - allow_population_by_field_name = True - validate_assignment = True - - def to_str(self) -> str: - return pprint.pformat(self.dict(by_alias=True)) - - def to_json(self) -> str: - return json.dumps(self.dict(by_alias=True, exclude_none=True)) - - @classmethod - def from_json(cls, json_str: str) -> "Task": - return cls.parse_raw(json_str) - - def to_dict(self) -> dict: - _dict = self.dict(by_alias=True, exclude_none=True) - if self.artifacts: - _dict["artifacts"] = [ - artifact.dict(by_alias=True, exclude_none=True) - for artifact in self.artifacts - ] - return _dict - - @classmethod - def from_dict(cls, obj: dict) -> "Task": - if obj is None: - return None - if not isinstance(obj, dict): - raise ValueError("Input must be a dictionary.") - if "artifacts" in obj: - obj["artifacts"] = [ - Artifact.parse_obj(artifact) for artifact in obj["artifacts"] - ] - return cls.parse_obj(obj) +# if child.id not in self.child_ids: +# self.child_ids.append(child.id) + +# if self.id not in child.parent_ids: +# child.parent_ids.append(self.id) + +# return child + +# def add_parent(self, parent: BaseTask) -> BaseTask: +# if self.structure: +# parent.structure = self.structure +# elif parent.structure: +# self.structure = parent.structure + +# if parent not in self.structure.tasks: +# self.structure.tasks.append(parent) + +# if self not in self.structure.tasks: +# self.structure.tasks.append(self) + +# if parent.id not in self.parent_ids: +# self.parent_ids.append(parent.id) + +# if self.id not in parent.child_ids: +# parent.child_ids.append(self.id) + +# return parent + +# def is_pending(self) -> bool: +# return self.state == self.State.PENDING + +# def is_finished(self) -> bool: +# return self.state == self.State.FINISHED + +# def is_executing(self) -> bool: +# return self.state == self.State.EXECUTING + +# def before_run(self) -> None: +# pass + +# def after_run(self) -> None: +# pass + +# def execute(self) -> Optional[Union[Artifact, ErrorArtifact]]: +# try: +# self.state = self.State.EXECUTING +# self.before_run() +# self.output = self.run() +# self.after_run() +# except Exception as e: +# self.output = ErrorArtifact(str(e)) +# finally: +# self.state = self.State.FINISHED +# return self.output + +# def can_execute(self) -> bool: +# return self.state == self.State.PENDING and all( +# parent.is_finished() for parent in self.parents +# ) + +# def reset(self) -> BaseTask: +# self.state = self.State.PENDING +# self.output = None +# return self + +# @abstractmethod +# def run(self) -> Optional[Union[Artifact, ErrorArtifact]]: +# pass + + +# class Task(BaseModel): +# input: Optional[StrictStr] = Field(None, description="Input prompt for the task") +# additional_input: Optional[Any] = Field( +# None, description="Input parameters for the task. Any value is allowed" +# ) +# task_id: StrictStr = Field(..., description="ID of the task") + +# class Config: +# allow_population_by_field_name = True +# validate_assignment = True + +# def to_str(self) -> str: +# return pprint.pformat(self.dict(by_alias=True)) + +# def to_json(self) -> str: +# return json.dumps(self.dict(by_alias=True, exclude_none=True)) + +# @classmethod +# def from_json(cls, json_str: str) -> "Task": +# return cls.parse_raw(json_str) + +# def to_dict(self) -> dict: +# _dict = self.dict(by_alias=True, exclude_none=True) +# if self.artifacts: +# _dict["artifacts"] = [ +# artifact.dict(by_alias=True, exclude_none=True) +# for artifact in self.artifacts +# ] +# return _dict + +# @classmethod +# def from_dict(cls, obj: dict) -> "Task": +# if obj is None: +# return None +# if not isinstance(obj, dict): +# raise ValueError("Input must be a dictionary.") +# if "artifacts" in obj: +# obj["artifacts"] = [ +# Artifact.parse_obj(artifact) for artifact in obj["artifacts"] +# ] +# return cls.parse_obj(obj) diff --git a/swarms/structs/workflow.py b/swarms/structs/workflow.py index 762ee6cc..31c95144 100644 --- a/swarms/structs/workflow.py +++ b/swarms/structs/workflow.py @@ -1,83 +1,84 @@ from __future__ import annotations import uuid -from concurrent.futures import ThreadPoolExecutor -from typing import Any, Dict, List, Optional -from swarms.structs.task import Task - - -class Workflow: - """ - Workflows are ideal for prescriptive processes that need to be executed - sequentially. - They string together multiple tasks of varying types, and can use Short-Term Memory - or pass specific arguments downstream. - - Usage - llm = LLM() - workflow = Workflow(llm) - - workflow.add("What's the weather in miami") - workflow.add("Provide details for {{ parent_output }}") - workflow.add("Summarize the above information: {{ parent_output}}) - - workflow.run() - - """ - - def __init__(self, agent, parallel: bool = False): - """__init__""" - self.agent = agent - self.tasks: List[Task] = [] - self.parallel = parallel - - def add(self, task: str) -> Task: - """Add a task""" - task = Task(task_id=uuid.uuid4().hex, input=task) - - if self.last_task(): - self.last_task().add_child(task) - else: - task.structure = self - self.tasks.append(task) - return task - - def first_task(self) -> Optional[Task]: - """Add first task""" - return self.tasks[0] if self.tasks else None - - def last_task(self) -> Optional[Task]: - """Last task""" - return self.tasks[-1] if self.tasks else None - - def run(self, task: str) -> Task: - """Run tasks""" - self.add(task) - - if self.parallel: - with ThreadPoolExecutor() as executor: - list(executor.map(self.__run_from_task, [self.first_task])) - else: - self.__run_from_task(self.first_task()) - - return self.last_task() - - def context(self, task: Task) -> Dict[str, Any]: - """Context in tasks""" - return { - "parent_output": task.parents[0].output - if task.parents and task.parents[0].output - else None, - "parent": task.parents[0] if task.parents else None, - "child": task.children[0] if task.children else None, - } - - def __run_from_task(self, task: Optional[Task]) -> None: - """Run from task""" - if task is None: - return - else: - if isinstance(task.execute(), Exception): - return - else: - self.__run_from_task(next(iter(task.children), None)) + +# from concurrent.futures import ThreadPoolExecutor +# from typing import Any, Dict, List, Optional +# # from swarms.structs.task import Task + + +# class Workflow: +# """ +# Workflows are ideal for prescriptive processes that need to be executed +# sequentially. +# They string together multiple tasks of varying types, and can use Short-Term Memory +# or pass specific arguments downstream. + +# Usage +# llm = LLM() +# workflow = Workflow(llm) + +# workflow.add("What's the weather in miami") +# workflow.add("Provide details for {{ parent_output }}") +# workflow.add("Summarize the above information: {{ parent_output}}) + +# workflow.run() + +# """ + +# def __init__(self, agent, parallel: bool = False): +# """__init__""" +# self.agent = agent +# self.tasks: List[Task] = [] +# self.parallel = parallel + +# def add(self, task: str) -> Task: +# """Add a task""" +# task = Task(task_id=uuid.uuid4().hex, input=task) + +# if self.last_task(): +# self.last_task().add_child(task) +# else: +# task.structure = self +# self.tasks.append(task) +# return task + +# def first_task(self) -> Optional[Task]: +# """Add first task""" +# return self.tasks[0] if self.tasks else None + +# def last_task(self) -> Optional[Task]: +# """Last task""" +# return self.tasks[-1] if self.tasks else None + +# def run(self, task: str) -> Task: +# """Run tasks""" +# self.add(task) + +# if self.parallel: +# with ThreadPoolExecutor() as executor: +# list(executor.map(self.__run_from_task, [self.first_task])) +# else: +# self.__run_from_task(self.first_task()) + +# return self.last_task() + +# def context(self, task: Task) -> Dict[str, Any]: +# """Context in tasks""" +# return { +# "parent_output": task.parents[0].output +# if task.parents and task.parents[0].output +# else None, +# "parent": task.parents[0] if task.parents else None, +# "child": task.children[0] if task.children else None, +# } + +# def __run_from_task(self, task: Optional[Task]) -> None: +# """Run from task""" +# if task is None: +# return +# else: +# if isinstance(task.execute(), Exception): +# return +# else: +# self.__run_from_task(next(iter(task.children), None)) diff --git a/swarms/swarms/autoscaler.py b/swarms/swarms/autoscaler.py index 48b3aa97..be79a860 100644 --- a/swarms/swarms/autoscaler.py +++ b/swarms/swarms/autoscaler.py @@ -14,8 +14,8 @@ class AutoScaler: """ The AutoScaler is like a kubernetes pod, that autoscales an agent or worker or boss! - Wraps around a structure like SequentialWorkflow - and or Flow and parallelizes them on multiple threads so they're split across devices + Wraps around a structure like SequentialWorkflow + and or Flow and parallelizes them on multiple threads so they're split across devices and you can use them like that Args: From a215bc5865892a2ee50331941db9d82eb3759691 Mon Sep 17 00:00:00 2001 From: Kye Date: Fri, 17 Nov 2023 20:24:19 -0800 Subject: [PATCH 2/8] new verison --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 04bdfe2f..df0e31ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "swarms" -version = "2.3.5" +version = "2.3.6" description = "Swarms - Pytorch" license = "MIT" authors = ["Kye Gomez "] From 9c92517b5c922589380fccc42a307c298ffb1eae Mon Sep 17 00:00:00 2001 From: Kye Date: Sat, 18 Nov 2023 12:25:02 -0800 Subject: [PATCH 3/8] agora --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3626c2dd..20d6d573 100644 --- a/README.md +++ b/README.md @@ -233,9 +233,11 @@ Swarms framework is not just a tool but a robust, scalable, and secure partner i - We're always looking for contributors to help us improve and expand this project. If you're interested, please check out our [Contributing Guidelines](CONTRIBUTING.md) and our [contributing board](https://github.com/users/kyegomez/projects/1) ## Community -- [Join the Swarms community here on Discord!](https://discord.gg/AJazBmhKnr) +- [Join the Swarms community on Discord!](https://discord.gg/AJazBmhKnr) +- Join our Swarms Community Gathering every Thursday at 1pm NYC Time to unlock the potential of autonomous agents in automating your daily tasks![Sign up here](https://lu.ma/5p2jnc2v) -# Discovery Call + +## Discovery Call Book a discovery call with the Swarms team to learn how to optimize and scale your swarm! [Click here to book a time that works for you!](https://calendly.com/swarm-corp/30min?month=2023-11) # License From 42b2cd631345b96dc467b38a5d182a6e0f5688f6 Mon Sep 17 00:00:00 2001 From: Kye Date: Sun, 19 Nov 2023 16:04:18 -0800 Subject: [PATCH 4/8] accountant swarm fixes --- .../demos/accountant_team/accountant_team.py | 111 ++++++++++++++---- playground/demos/paper_to_code.py | 19 +++ playground/structs/fuyu_flow.py | 10 ++ playground/structs/multi_modal_flow.py | 14 +++ swarms/structs/flow.py | 56 +++++++-- swarms/structs/sequential_workflow.py | 4 + 6 files changed, 179 insertions(+), 35 deletions(-) create mode 100644 playground/demos/paper_to_code.py create mode 100644 playground/structs/fuyu_flow.py create mode 100644 playground/structs/multi_modal_flow.py diff --git a/playground/demos/accountant_team/accountant_team.py b/playground/demos/accountant_team/accountant_team.py index 7eadec96..0c1dd6eb 100644 --- a/playground/demos/accountant_team/accountant_team.py +++ b/playground/demos/accountant_team/accountant_team.py @@ -1,35 +1,96 @@ -import re from swarms.models.nougat import Nougat from swarms.structs import Flow -from swarms.models import OpenAIChat -from swarms.models import LayoutLMDocumentQA +from swarms.models import OpenAIChat, Anthropic +from typing import List -# # URL of the image of the financial document -IMAGE_OF_FINANCIAL_DOC_URL = "bank_statement_2.jpg" -# Example usage -api_key = "" +# Base llms +llm1 = OpenAIChat() +llm2 = Anthropic() +nougat = Nougat() -# Initialize the language flow -llm = OpenAIChat( - openai_api_key=api_key, -) -# LayoutLM Document QA -pdf_analyzer = LayoutLMDocumentQA() +# Prompts for each agent +SUMMARY_AGENT_PROMPT = """ + Generate an actionable summary of this financial document be very specific and precise, provide bulletpoints be very specific provide methods of lowering expenses: {answer}" +""" + -question = "What is the total amount of expenses?" -answer = pdf_analyzer( - question, - IMAGE_OF_FINANCIAL_DOC_URL, +# Agents +user_consultant_agent = Flow( + llm=llm1, +) +doc_analyzer_agent = Flow( + llm=llm1, +) +summary_generator_agent = Flow( + llm=llm2, +) +fraud_detection_agent = Flow( + llm=llm2, +) +decision_making_support_agent = Flow( + llm=llm2, ) -# Initialize the Flow with the language flow -agent = Flow(llm=llm) -SUMMARY_AGENT_PROMPT = f""" -Generate an actionable summary of this financial document be very specific and precise, provide bulletpoints be very specific provide methods of lowering expenses: {answer}" -""" -# Add tasks to the workflow -summary_agent = agent.run(SUMMARY_AGENT_PROMPT) -print(summary_agent) +class AccountantSwarms: + """ + Accountant Swarms is a collection of agents that work together to help + accountants with their work. + + Flow: analyze doc -> detect fraud -> generate summary -> decision making support + + The agents are: + - User Consultant: Asks the user many questions + - Document Analyzer: Extracts text from the image of the financial document + - Fraud Detection: Detects fraud in the document + - Summary Agent: Generates an actionable summary of the document + - Decision Making Support: Provides decision making support to the accountant + + The agents are connected together in a workflow that is defined in the + run method. + + The workflow is as follows: + 1. The Document Analyzer agent extracts text from the image of the + financial document. + 2. The Fraud Detection agent detects fraud in the document. + 3. The Summary Agent generates an actionable summary of the document. + 4. The Decision Making Support agent provides decision making support + to the accountant. + + Example: + >>> accountant_swarms = AccountantSwarms( + + + """ + + def __init__( + self, + financial_document_img: str, + financial_document_list_img: List[str] = None, + fraud_detection_instructions: str = None, + summary_agent_instructions: str = None, + decision_making_support_agent_instructions: str = None, + ): + super().__init__() + self.financial_document_img = financial_document_img + self.fraud_detection_instructions = fraud_detection_instructions + self.summary_agent_instructions = summary_agent_instructions + + def run(self): + # Extract text from the image + analyzed_doc = self.nougat(self.financial_document_img) + + # Detect fraud in the document + fraud_detection_agent_output = self.fraud_detection_agent(analyzed_doc) + + # Generate an actionable summary of the document + summary_agent_output = self.summary_agent(fraud_detection_agent_output) + + # Provide decision making support to the accountant + decision_making_support_agent_output = self.decision_making_support_agent( + summary_agent_output + ) + + return decision_making_support_agent_output diff --git a/playground/demos/paper_to_code.py b/playground/demos/paper_to_code.py new file mode 100644 index 00000000..250653f4 --- /dev/null +++ b/playground/demos/paper_to_code.py @@ -0,0 +1,19 @@ +from swarms.structs import Flow, SequentialWorkflow +from swarms.models import OpenAIChat, Anthropic + +# llm +llm = OpenAIChat() +llm2 = Anthropic() + +# 2 Flows, one that creates an algorithmic pseuedocode and another that creates the pytorch code +flow1 = Flow(llm2, max_loops=1) +flow2 = Flow(llm, max_loops=1) + +# SequentialWorkflow +workflow = SequentialWorkflow( + [flow1, flow2], + max_loops=1, + name="Paper to Code", + autosave=True, + description="This workflow takes a paper and converts it to code.", +) diff --git a/playground/structs/fuyu_flow.py b/playground/structs/fuyu_flow.py new file mode 100644 index 00000000..6f4dca5f --- /dev/null +++ b/playground/structs/fuyu_flow.py @@ -0,0 +1,10 @@ +from swarms import Flow, Fuyu + +llm = Fuyu() + +flow = Flow(max_loops="auto", llm=llm) + +flow.run( + task="Describe this image in a few sentences: ", + img="https://unsplash.com/photos/0pIC5ByPpZY", +) diff --git a/playground/structs/multi_modal_flow.py b/playground/structs/multi_modal_flow.py new file mode 100644 index 00000000..d746d98f --- /dev/null +++ b/playground/structs/multi_modal_flow.py @@ -0,0 +1,14 @@ +# This might not work in the beginning but it's a starting point +from swarms.structs import Flow, GPT4V + +llm = GPT4V() + +flow = Flow( + max_loops="auto", + llm=llm, +) + +flow.run( + task="Describe this image in a few sentences: ", + img="https://unsplash.com/photos/0pIC5ByPpZY", +) diff --git a/swarms/structs/flow.py b/swarms/structs/flow.py index a2711e20..ba060b8b 100644 --- a/swarms/structs/flow.py +++ b/swarms/structs/flow.py @@ -46,6 +46,7 @@ commands: { } } +-------------TOOLS--------------------------- {tools} """ @@ -149,14 +150,16 @@ class Flow: dynamic_loops: Optional[bool] = False, interactive: bool = False, dashboard: bool = False, - agent_name: str = "Flow agent", + agent_name: str = " Autonomous Agent XYZ1B", system_prompt: str = FLOW_SYSTEM_PROMPT, # tools: List[Any] = None, dynamic_temperature: bool = False, + SOP: str = None, saved_state_path: Optional[str] = "flow_state.json", autosave: bool = False, context_length: int = 8192, - user_name: str = "Human", + user_name: str = "Human:", + self_healing: bool = False, **kwargs: Any, ): self.llm = llm @@ -175,6 +178,9 @@ class Flow: self.dynamic_temperature = dynamic_temperature self.dynamic_loops = dynamic_loops self.user_name = user_name + self.context_length = context_length + # SOPS to inject into the system prompt + self.SOP = SOP # The max_loops will be set dynamically if the dynamic_loop if self.dynamic_loops: self.max_loops = "auto" @@ -184,6 +190,7 @@ class Flow: self.saved_state_path = saved_state_path self.autosave = autosave self.response_filters = [] + self.self_healing = self_healing def provide_feedback(self, feedback: str) -> None: """Allow users to provide feedback on the responses.""" @@ -688,14 +695,6 @@ class Flow: return "Timeout" return response - # def backup_memory_to_s3(self, bucket_name: str, object_name: str): - # """Backup the memory to S3""" - # import boto3 - - # s3 = boto3.client("s3") - # s3.put_object(Bucket=bucket_name, Key=object_name, Body=json.dumps(self.memory)) - # print(f"Backed up memory to S3: {bucket_name}/{object_name}") - def analyze_feedback(self): """Analyze the feedback for issues""" feedback_counts = {} @@ -920,3 +919,40 @@ class Flow: def update_retry_interval(self, retry_interval: int): """Update the retry interval""" self.retry_interval = retry_interval + + def self_healing(self, **kwargs): + """ + Self healing by debugging errors and refactoring its own code + + Args: + **kwargs (Any): Any additional keyword arguments + """ + # Run the flow + response = self.run_with_timeout("flow") + + # If an error occurs, save the state + if not self.validate_response(response): + self.save_state("previous_state.txt") + + # Refactor the code + self.refactor_code() + + # Run the flow again + response = self.run_with_timeout("flow") + + # If the error occurs again, revert to the previous state + if not self.validate_response(response): + self.load_state("previous_state.txt") + + # If the error does not occur, continue + else: + print("Self-healing successful! Bug fixed!") + + return response + + def refactor_code(self): + """ + Refactor the code + """ + # Add your code here to refactor the code + pass diff --git a/swarms/structs/sequential_workflow.py b/swarms/structs/sequential_workflow.py index 8c7d9760..d1c600f0 100644 --- a/swarms/structs/sequential_workflow.py +++ b/swarms/structs/sequential_workflow.py @@ -107,6 +107,8 @@ class SequentialWorkflow: tasks: List[Task] = field(default_factory=list) max_loops: int = 1 autosave: bool = False + name: str = (None,) + description: str = (None,) saved_state_filepath: Optional[str] = "sequential_workflow_state.json" restore_state_filepath: Optional[str] = None dashboard: bool = False @@ -248,6 +250,8 @@ class SequentialWorkflow: f""" Sequential Workflow Dashboard -------------------------------- + Name: {self.name} + Description: {self.description} Tasks: {len(self.tasks)} Max Loops: {self.max_loops} Autosave: {self.autosave} From 7ee4fe323bc426a55a2af78016d05aa5ee4867e9 Mon Sep 17 00:00:00 2001 From: Kye Date: Sun, 19 Nov 2023 16:41:56 -0800 Subject: [PATCH 5/8] clean up of pdf to text and acount swarm --- .../demos/accountant_team/accountant_team.py | 42 +++-- playground/worker/ultranode_example.py | 15 -- playground/worker/worker.py | 17 -- playground/worker/worker_auto.py | 15 -- playground/worker/worker_ultra.py | 25 --- pyproject.toml | 3 +- requirements.txt | 1 + swarms/structs/flow.py | 176 ++++++++++-------- swarms/utils/__init__.py | 2 + swarms/utils/pdf_to_text.py | 44 +++++ 10 files changed, 177 insertions(+), 163 deletions(-) delete mode 100644 playground/worker/ultranode_example.py delete mode 100644 playground/worker/worker.py delete mode 100644 playground/worker/worker_auto.py delete mode 100644 playground/worker/worker_ultra.py create mode 100644 swarms/utils/pdf_to_text.py diff --git a/playground/demos/accountant_team/accountant_team.py b/playground/demos/accountant_team/accountant_team.py index 0c1dd6eb..1401ef32 100644 --- a/playground/demos/accountant_team/accountant_team.py +++ b/playground/demos/accountant_team/accountant_team.py @@ -1,13 +1,27 @@ -from swarms.models.nougat import Nougat -from swarms.structs import Flow -from swarms.models import OpenAIChat, Anthropic +import os from typing import List +from dotenv import load_dotenv + +from swarms.models import Anthropic, OpenAIChat +from swarms.structs import Flow +from swarms.utils.pdf_to_text import pdf_to_text + + +# Environment variables +load_dotenv() +anthropic_api_key = os.getenv("ANTHROPIC_API_KEY") +openai_api_key = os.getenv("OPENAI_API_KEY") + # Base llms -llm1 = OpenAIChat() -llm2 = Anthropic() -nougat = Nougat() +llm1 = OpenAIChat( + openai_api_key=openai_api_key, +) + +llm2 = Anthropic( + anthropic_api_key=anthropic_api_key, +) # Prompts for each agent @@ -67,23 +81,27 @@ class AccountantSwarms: def __init__( self, - financial_document_img: str, - financial_document_list_img: List[str] = None, + pdf_path: str, + list_pdfs: List[str] = None, fraud_detection_instructions: str = None, summary_agent_instructions: str = None, decision_making_support_agent_instructions: str = None, ): super().__init__() - self.financial_document_img = financial_document_img + self.pdf_path = pdf_path + self.list_pdfs = list_pdfs self.fraud_detection_instructions = fraud_detection_instructions self.summary_agent_instructions = summary_agent_instructions + self.decision_making_support_agent_instructions = ( + decision_making_support_agent_instructions + ) def run(self): - # Extract text from the image - analyzed_doc = self.nougat(self.financial_document_img) + # Transform the pdf to text + pdf_text = pdf_to_text(self.pdf_path) # Detect fraud in the document - fraud_detection_agent_output = self.fraud_detection_agent(analyzed_doc) + fraud_detection_agent_output = self.fraud_detection_agent(pdf_text) # Generate an actionable summary of the document summary_agent_output = self.summary_agent(fraud_detection_agent_output) diff --git a/playground/worker/ultranode_example.py b/playground/worker/ultranode_example.py deleted file mode 100644 index 4bd1d80c..00000000 --- a/playground/worker/ultranode_example.py +++ /dev/null @@ -1,15 +0,0 @@ -from swarms import WorkerUltraUltraNode - -# Define an objective -objective = """ -Please make a web GUI for using HTTP API server. -The name of it is Swarms. -You can check the server code at ./main.py. -The server is served on localhost:8000. -Users should be able to write text input as 'query' and url array as 'files', and check the response. -Users input form should be delivered in JSON format. -I want it to have neumorphism-style. Serve it on port 4500. -""" - -node = WorkerUltraUltraNode(objective) -result = node.execute() diff --git a/playground/worker/worker.py b/playground/worker/worker.py deleted file mode 100644 index 00f15f1a..00000000 --- a/playground/worker/worker.py +++ /dev/null @@ -1,17 +0,0 @@ -from langchain.models import OpenAIChat -from swarms import Worker - -llm = OpenAIChat(model_name="gpt-4", openai_api_key="api-key", temperature=0.5) - -node = Worker( - llm=llm, - ai_name="Optimus Prime", - ai_role="Worker in a swarm", - external_tools=None, - human_in_the_loop=False, - temperature=0.5, -) - -task = "What were the winning boston marathon times for the past 5 years (ending in 2022)? Generate a table of the year, name, country of origin, and times." -response = node.run(task) -print(response) diff --git a/playground/worker/worker_auto.py b/playground/worker/worker_auto.py deleted file mode 100644 index 3b7e0c16..00000000 --- a/playground/worker/worker_auto.py +++ /dev/null @@ -1,15 +0,0 @@ -from swarms import worker_node - -# Your OpenAI API key -api_key = "sksdsds" - -# Initialize a WorkerNode with your API key -node = worker_node(api_key) - -# Define an objective -objective = "Please make a web GUI for using HTTP API server..." - -# Run the task -task = node.run(objective) - -print(task) diff --git a/playground/worker/worker_ultra.py b/playground/worker/worker_ultra.py deleted file mode 100644 index 69da3f30..00000000 --- a/playground/worker/worker_ultra.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -from swarms.swarms.swarms import WorkerUltra - -api_key = os.getenv("OPENAI_API_KEY") - -# Define an objective -objective = """ -Please make a web GUI for using HTTP API server. -The name of it is Swarms. -You can check the server code at ./main.py. -The server is served on localhost:8000. -Users should be able to write text input as 'query' and url array as 'files', and check the response. -Users input form should be delivered in JSON format. -I want it to have neumorphism-style. Serve it on port 4500. - -""" - -# Create an instance of WorkerUltra -worker = WorkerUltra(objective, api_key) - -# Execute the task -result = worker.execute() - -# Print the result -print(result) diff --git a/pyproject.toml b/pyproject.toml index df0e31ab..c96f5119 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "swarms" -version = "2.3.6" +version = "2.3.7" description = "Swarms - Pytorch" license = "MIT" authors = ["Kye Gomez "] @@ -39,6 +39,7 @@ backoff = "*" marshmallow = "*" datasets = "*" diffusers = "*" +PyPDF2 = "*" accelerate = "*" sentencepiece = "*" wget = "*" diff --git a/requirements.txt b/requirements.txt index 8dad8dc6..b6a1d69a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -27,6 +27,7 @@ huggingface-hub google-generativeai sentencepiece duckduckgo-search +PyPDF2 agent-protocol accelerate chromadb diff --git a/swarms/structs/flow.py b/swarms/structs/flow.py index ba060b8b..171cafc9 100644 --- a/swarms/structs/flow.py +++ b/swarms/structs/flow.py @@ -151,10 +151,11 @@ class Flow: interactive: bool = False, dashboard: bool = False, agent_name: str = " Autonomous Agent XYZ1B", + agent_description: str = None, system_prompt: str = FLOW_SYSTEM_PROMPT, # tools: List[Any] = None, dynamic_temperature: bool = False, - SOP: str = None, + sop: str = None, saved_state_path: Optional[str] = "flow_state.json", autosave: bool = False, context_length: int = 8192, @@ -180,13 +181,14 @@ class Flow: self.user_name = user_name self.context_length = context_length # SOPS to inject into the system prompt - self.SOP = SOP + self.sop = sop # The max_loops will be set dynamically if the dynamic_loop if self.dynamic_loops: self.max_loops = "auto" # self.tools = tools or [] self.system_prompt = system_prompt self.agent_name = agent_name + self.agent_description = agent_description self.saved_state_path = saved_state_path self.autosave = autosave self.response_filters = [] @@ -402,77 +404,81 @@ class Flow: 5. Repeat until stopping condition is met or max_loops is reached """ - # dynamic_prompt = self.construct_dynamic_prompt() - # combined_prompt = f"{dynamic_prompt}\n{task}" - - # Activate Autonomous agent message - self.activate_autonomous_agent() - - response = task # or combined_prompt - history = [f"{self.user_name}: {task}"] - - # If dashboard = True then print the dashboard - if self.dashboard: - self.print_dashboard(task) - - loop_count = 0 - # for i in range(self.max_loops): - while self.max_loops == "auto" or loop_count < self.max_loops: - loop_count += 1 - print(colored(f"\nLoop {loop_count} of {self.max_loops}", "blue")) - print("\n") - - if self.stopping_token: - if self._check_stopping_condition(response) or parse_done_token( - response - ): - break - - # Adjust temperature, comment if no work - if self.dynamic_temperature: - self.dynamic_temperature() - - # Preparing the prompt - task = self.agent_history_prompt(FLOW_SYSTEM_PROMPT, response) - - attempt = 0 - while attempt < self.retry_attempts: - try: - response = self.llm( - task, - **kwargs, - ) - # If there are any tools then parse and execute them - # if self.tools: - # self.parse_and_execute_tools(response) - - if self.interactive: - print(f"AI: {response}") - history.append(f"AI: {response}") - response = input("You: ") - history.append(f"Human: {response}") - else: - print(f"AI: {response}") - history.append(f"AI: {response}") - print(response) - break - except Exception as e: - logging.error(f"Error generating response: {e}") - attempt += 1 - time.sleep(self.retry_interval) - history.append(response) - time.sleep(self.loop_interval) - self.memory.append(history) - - if self.autosave: - save_path = self.saved_state_path or "flow_state.json" - print(colored(f"Autosaving flow state to {save_path}", "green")) - self.save_state(save_path) - - if self.return_history: - return response, history + try: + # dynamic_prompt = self.construct_dynamic_prompt() + # combined_prompt = f"{dynamic_prompt}\n{task}" + + # Activate Autonomous agent message + self.activate_autonomous_agent() + + response = task # or combined_prompt + history = [f"{self.user_name}: {task}"] + + # If dashboard = True then print the dashboard + if self.dashboard: + self.print_dashboard(task) + + loop_count = 0 + # for i in range(self.max_loops): + while self.max_loops == "auto" or loop_count < self.max_loops: + loop_count += 1 + print(colored(f"\nLoop {loop_count} of {self.max_loops}", "blue")) + print("\n") + + if self.stopping_token: + if self._check_stopping_condition(response) or parse_done_token( + response + ): + break + + # Adjust temperature, comment if no work + if self.dynamic_temperature: + self.dynamic_temperature() + + # Preparing the prompt + task = self.agent_history_prompt(FLOW_SYSTEM_PROMPT, response) + + attempt = 0 + while attempt < self.retry_attempts: + try: + response = self.llm( + task, + **kwargs, + ) + # If there are any tools then parse and execute them + # if self.tools: + # self.parse_and_execute_tools(response) + + if self.interactive: + print(f"AI: {response}") + history.append(f"AI: {response}") + response = input("You: ") + history.append(f"Human: {response}") + else: + print(f"AI: {response}") + history.append(f"AI: {response}") + print(response) + break + except Exception as e: + logging.error(f"Error generating response: {e}") + attempt += 1 + time.sleep(self.retry_interval) + history.append(response) + time.sleep(self.loop_interval) + self.memory.append(history) + + if self.autosave: + save_path = self.saved_state_path or "flow_state.json" + print(colored(f"Autosaving flow state to {save_path}", "green")) + self.save_state(save_path) + + if self.return_history: + return response, history - return response + return response + except Exception as error: + print(f"Error running flow: {error}") + raise async def arun(self, task: str, **kwargs): """ @@ -572,13 +578,27 @@ class Flow: Returns: str: The agent history prompt """ - system_prompt = system_prompt or self.system_prompt - agent_history_prompt = f""" - SYSTEM_PROMPT: {system_prompt} + if self.sop: + system_prompt = system_prompt or self.system_prompt + agent_history_prompt = f""" + SYSTEM_PROMPT: {system_prompt} + + Follow this standard operating procedure (SOP) to complete tasks: + {self.sop} + + ----------------- + History of conversations between yourself and your user {self.user_name}: {history} + """ + return agent_history_prompt + else: + system_prompt = system_prompt or self.system_prompt + agent_history_prompt = f""" + SYSTEM_PROMPT: {system_prompt} - History: {history} - """ - return agent_history_prompt + + History: {history} + """ + return agent_history_prompt async def run_concurrent(self, tasks: List[str], **kwargs): """ diff --git a/swarms/utils/__init__.py b/swarms/utils/__init__.py index da323121..d5ce3583 100644 --- a/swarms/utils/__init__.py +++ b/swarms/utils/__init__.py @@ -2,10 +2,12 @@ from swarms.utils.display_markdown import display_markdown_message from swarms.utils.futures import execute_futures_dict from swarms.utils.code_interpreter import SubprocessCodeInterpreter from swarms.utils.parse_code import extract_code_in_backticks_in_string +from swarms.utils.pdf_to_text import pdf_to_text __all__ = [ "display_markdown_message", "execute_futures_dict", "SubprocessCodeInterpreter", "extract_code_in_backticks_in_string", + "pdf_to_text", ] diff --git a/swarms/utils/pdf_to_text.py b/swarms/utils/pdf_to_text.py new file mode 100644 index 00000000..9d0f97b8 --- /dev/null +++ b/swarms/utils/pdf_to_text.py @@ -0,0 +1,44 @@ +import sys +import os + +try: + import PyPDF2 +except ImportError: + print("PyPDF2 not installed. Please install it using: pip install PyPDF2") + sys.exit(1) + + + +def pdf_to_text(pdf_path): + """ + Converts a PDF file to a string of text. + + Args: + pdf_path (str): The path to the PDF file to be converted. + + Returns: + str: The text extracted from the PDF. + + Raises: + FileNotFoundError: If the PDF file is not found at the specified path. + Exception: If there is an error in reading the PDF file. + """ + try: + # Open the PDF file + with open(pdf_path, 'rb') as file: + pdf_reader = PyPDF2.PdfReader(file) + text = "" + + # Iterate through each page and extract text + for page in pdf_reader.pages: + text += page.extract_text() + "\n" + + return text + except FileNotFoundError: + raise FileNotFoundError(f"The file at {pdf_path} was not found.") + except Exception as e: + raise Exception(f"An error occurred while reading the PDF file: {e}") + +# Example usage +# text = pdf_to_text("test.pdf") +# print(text) \ No newline at end of file From be62f09bb56d7745d90b6de74ba54e1d5b93c2fd Mon Sep 17 00:00:00 2001 From: Kye Date: Sun, 19 Nov 2023 20:03:26 -0800 Subject: [PATCH 6/8] ai researh team swarm --- .../demos/accountant_team/account_team2.py | 74 ++++++++++++++ .../demos/accountant_team/accountant_team.py | 47 ++++----- playground/demos/ai_research_team/main.py | 50 ++++++++++ .../__pycache__/PosMedPrompts.cpython-310.pyc | Bin 3831 -> 0 bytes swarms/prompts/accountant_swarm_prompts.py | 90 +++++++++++++++++ swarms/prompts/ai_research_team.py | 91 ++++++++++++++++++ swarms/structs/flow.py | 6 +- swarms/utils/pdf_to_text.py | 6 +- 8 files changed, 336 insertions(+), 28 deletions(-) create mode 100644 playground/demos/accountant_team/account_team2.py create mode 100644 playground/demos/ai_research_team/main.py delete mode 100644 playground/posmed/__pycache__/PosMedPrompts.cpython-310.pyc create mode 100644 swarms/prompts/accountant_swarm_prompts.py create mode 100644 swarms/prompts/ai_research_team.py diff --git a/playground/demos/accountant_team/account_team2.py b/playground/demos/accountant_team/account_team2.py new file mode 100644 index 00000000..db3e6ed6 --- /dev/null +++ b/playground/demos/accountant_team/account_team2.py @@ -0,0 +1,74 @@ +import os +from dotenv import load_dotenv +from swarms.models import Anthropic, OpenAIChat +from swarms.prompts.accountant_swarm_prompts import ( + DECISION_MAKING_PROMPT, + DOC_ANALYZER_AGENT_PROMPT, + FRAUD_DETECTION_AGENT_PROMPT, + SUMMARY_GENERATOR_AGENT_PROMPT, +) +from swarms.structs import Flow +from swarms.utils.pdf_to_text import pdf_to_text + +# Environment variables +load_dotenv() +anthropic_api_key = os.getenv("ANTHROPIC_API_KEY") +openai_api_key = os.getenv("OPENAI_API_KEY") + + +# Base llms +llm1 = OpenAIChat( + openai_api_key=openai_api_key, +) + +llm2 = Anthropic( + anthropic_api_key=anthropic_api_key, +) + + +# Agents +doc_analyzer_agent = Flow( + llm=llm2, + sop=DOC_ANALYZER_AGENT_PROMPT, + max_loops="auto", +) +summary_generator_agent = Flow( + llm=llm2, + sop=SUMMARY_GENERATOR_AGENT_PROMPT, + max_loops="auto", +) +decision_making_support_agent = Flow( + llm=llm2, + sop=DECISION_MAKING_PROMPT, + max_loops="auto", +) + + +pdf_path="swarmdeck_a1.pdf" +fraud_detection_instructions="Detect fraud in the document" +summary_agent_instructions="Generate an actionable summary of the document" +decision_making_support_agent_instructions="Provide decision making support to the business owner:" + + +# Transform the pdf to text +pdf_text = pdf_to_text(pdf_path) +print(pdf_text) + + +# Detect fraud in the document +fraud_detection_agent_output = doc_analyzer_agent.run( + f"{fraud_detection_instructions}: {pdf_text}" +) +print(fraud_detection_agent_output) + +# Generate an actionable summary of the document +summary_agent_output = summary_generator_agent.run( + f"{summary_agent_instructions}: {fraud_detection_agent_output}" +) +print(summary_agent_output) + +# Provide decision making support to the accountant +decision_making_support_agent_output = decision_making_support_agent.run( + f"{decision_making_support_agent_instructions}: {summary_agent_output}" +) +print(decision_making_support_agent_output) \ No newline at end of file diff --git a/playground/demos/accountant_team/accountant_team.py b/playground/demos/accountant_team/accountant_team.py index 1401ef32..61cc2f7a 100644 --- a/playground/demos/accountant_team/accountant_team.py +++ b/playground/demos/accountant_team/accountant_team.py @@ -4,10 +4,15 @@ from typing import List from dotenv import load_dotenv from swarms.models import Anthropic, OpenAIChat +from swarms.prompts.accountant_swarm_prompts import ( + DECISION_MAKING_PROMPT, + DOC_ANALYZER_AGENT_PROMPT, + FRAUD_DETECTION_AGENT_PROMPT, + SUMMARY_GENERATOR_AGENT_PROMPT, +) from swarms.structs import Flow from swarms.utils.pdf_to_text import pdf_to_text - # Environment variables load_dotenv() anthropic_api_key = os.getenv("ANTHROPIC_API_KEY") @@ -24,27 +29,18 @@ llm2 = Anthropic( ) -# Prompts for each agent -SUMMARY_AGENT_PROMPT = """ - Generate an actionable summary of this financial document be very specific and precise, provide bulletpoints be very specific provide methods of lowering expenses: {answer}" -""" - - # Agents -user_consultant_agent = Flow( - llm=llm1, -) doc_analyzer_agent = Flow( llm=llm1, + sop=DOC_ANALYZER_AGENT_PROMPT, ) summary_generator_agent = Flow( llm=llm2, -) -fraud_detection_agent = Flow( - llm=llm2, + sop=SUMMARY_GENERATOR_AGENT_PROMPT, ) decision_making_support_agent = Flow( llm=llm2, + sop=DECISION_MAKING_PROMPT, ) @@ -71,11 +67,6 @@ class AccountantSwarms: 2. The Fraud Detection agent detects fraud in the document. 3. The Summary Agent generates an actionable summary of the document. 4. The Decision Making Support agent provides decision making support - to the accountant. - - Example: - >>> accountant_swarms = AccountantSwarms( - """ @@ -101,14 +92,26 @@ class AccountantSwarms: pdf_text = pdf_to_text(self.pdf_path) # Detect fraud in the document - fraud_detection_agent_output = self.fraud_detection_agent(pdf_text) + fraud_detection_agent_output = doc_analyzer_agent.run( + f"{self.fraud_detection_instructions}: {pdf_text}" + ) # Generate an actionable summary of the document - summary_agent_output = self.summary_agent(fraud_detection_agent_output) + summary_agent_output = summary_generator_agent.run( + f"{self.summary_agent_instructions}: {fraud_detection_agent_output}" + ) # Provide decision making support to the accountant - decision_making_support_agent_output = self.decision_making_support_agent( - summary_agent_output + decision_making_support_agent_output = decision_making_support_agent.run( + f"{self.decision_making_support_agent_instructions}: {summary_agent_output}" ) return decision_making_support_agent_output + + +swarm = AccountantSwarms( + pdf_path="tesla.pdf", + fraud_detection_instructions="Detect fraud in the document", + summary_agent_instructions="Generate an actionable summary of the document", + decision_making_support_agent_instructions="Provide decision making support to the business owner:", +) diff --git a/playground/demos/ai_research_team/main.py b/playground/demos/ai_research_team/main.py new file mode 100644 index 00000000..c986e123 --- /dev/null +++ b/playground/demos/ai_research_team/main.py @@ -0,0 +1,50 @@ +import os + +from dotenv import load_dotenv + +from swarms.models import Anthropic, OpenAIChat +from swarms.prompts.ai_research_team import ( + PAPER_IMPLEMENTOR_AGENT_PROMPT, + PAPER_SUMMARY_ANALYZER, +) +from swarms.structs import Flow +from swarms.utils.pdf_to_text import pdf_to_text + +# Base llms +# Environment variables +load_dotenv() +anthropic_api_key = os.getenv("ANTHROPIC_API_KEY") +openai_api_key = os.getenv("OPENAI_API_KEY") + +PDF_PATH = "shallowfeedforward.pdf" + + +# Base llms +llm1 = OpenAIChat( + openai_api_key=openai_api_key, +) + +llm2 = Anthropic( + anthropic_api_key=anthropic_api_key, +) + +# Agents +paper_summarizer_agent = Flow( + llm=llm2, + sop=PAPER_SUMMARY_ANALYZER, + max_loops=1, + autosave=True, + saved_state_path='paper_summarizer.json' +) + +paper_implementor_agent = Flow( + llm=llm1, + sop=PAPER_IMPLEMENTOR_AGENT_PROMPT, + max_loops=1, + autosave=True, + saved_state_path='paper_implementor.json' +) + +paper = pdf_to_text(PDF_PATH) +algorithmic_psuedocode_agent = paper_summarizer_agent.run(paper) +pytorch_code = paper_implementor_agent.run(algorithmic_psuedocode_agent) \ No newline at end of file diff --git a/playground/posmed/__pycache__/PosMedPrompts.cpython-310.pyc b/playground/posmed/__pycache__/PosMedPrompts.cpython-310.pyc deleted file mode 100644 index 4bcfbb742219abb8adcc40120ef2f5505e351060..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 zcmZXX&u$yZ5ymN5UfZ;HlS2aJu!qJvL1IAU%HGXISZtzb30r{vMUvN8M>#ZSn!^rf zrpMhgq-k3~4ta^(vd272-ayCXEpp1QdWMvY5a0}_r@Ol9tFOLlx=%mt_xODN^*83( zXT9Ek8L+mn_0%=BGH(+xN<5|* zn>@E+TCjH5?_W#}dsjAL^Ii4+{l&@Y!T!}%zyDZ0A03a*_72tamj~aC4iAn;G8umZ zCi7H{%{uOmB_)MR?Zg_-6v;^9^4z^?tOj~97PB;WHdWqK zrp7F}>5RsgO=j)FhK|@_*dRl#;fzu3C3|rL)-008l{6O8W8uEi+G!wT0_B9y|_3!l-HOGcAQfz zF+Fc}QON@V))RM6nXOD}^>D=~9cJuhLd;$C8{(D97KKc!4X|XftX1Zm6pEy# zOe|R^y9?uS$dT$uPZ(znc@geT&;y`PRVZym#uTOY+_@|_?9Ka?9(2WF%Or176QM0Y zZjhRgcw5C1{Y}x3iPaRb{-@KklcUp%Kd&m~*6b%j7Ije8-le1;`gQD43DC|4XiYs` zN>Tb+K_nbfdwFo%>Lo#m@nCR!W|pE#f?5p6dR%z%Y}nt+7kVjTMGRn3j4i|yA))>% z?RDmLH6=e?UIno>Wijm<8K_AbG}b9M^A4_r7jBu1IdhmZ>Go=QgwLJilvnL1p1G4GLwp>7a}cE>j;|HllsPMmhU6dWR-|2dM48` zV#=(Z0=mOV@dhf&VgRO+N=yr)wm?berfaE>)hNcTI>(g4_K0{J1PJ3GO|;$iQ9HeN z(kL=rNqR}MH}nc}s8cL~8uO*wYoAPqx8lqiAe7dCuU#EFpXt)R6R+0&B6>W@-9pyx z1^Si*R3g@NAXZC2V{nxgYP0etj5bp@`0k;uBBb!POJl&VoUjlDXxyEN+VcbhU5?oy zNl09>6j8Z#SP_4|m#i;|bS|z;q)#q_GW9g>A`u!%8Rw@YF_r8zhWpgO$`LfH;Mi6# zhbkg{26j~As^vsHbE!Sfbg3QN*h(Z=Z=x&gD&-WbEN~)vtPUd`Z)XptO{_206qllr z(6ff%9o=GG8nM)nw46Fma&3$D;Fnw7?d)xsu?>kxQ*tV=mspZ0aFXzF65CRlq&^eM zw7KD+(9~@qijC;$AG^-DKQ+lr6na;w^Tao(p?wFMQ7t3Wl+LuJDsGqhucgpILfXER z57i$*UuSEej8Jnh@djh4RQQqwHT%S-9-6A6>)>-2DK-vW7HtUK)If#8Igq$HJ3(_o z<)k1i(}G-gcIt8$yNJ|^VKolZ|LaMUgHm^-9h;>id6T@EK$}i;*!T}06PVRamD@?% z7b4kX!;Obvv_EKCNyfT!8Y{(uAv$){=>gO#oR@RST4Zq>qMNx!5=)LL0B5T3B?&|a zIa_xME8Yj8(B9d_!T#Y$U7V=1(f0?VSG)c9@4LbFbba#j;`HUkZvV^-+CC|q?kY%5 zMYAX@rIZy%wuXI034PQ$0VW;>k%sP%#VU{eME(h_K6m)B#dn`?_yw1`_m7Qq<3sPq zP41f?Hh$c^+WfG|zoI+G?;fmsWc>MJbTqoUda`-_FcJuDEvowZ9yH8#VxHW&z8mYD z+mvKpe}V)u;h#NEH|qWO#s2Ok2M`}FgAP-BdAg*L`vNO+SY~v=Q@F&|GV_F&UUHtK zq%Ubj@UY!246Eh!XPK$L6RmE?b|n;v>1P{T8~#2&k_|4ak3_$Y_@_MFM0~aJVS`9F zkKaAKl?wuV)S}wj_hNy;dtEO4U7ll1?d2Yi*FV9hRv+3$-!d4TdL&Lg Date: Sun, 19 Nov 2023 20:23:11 -0800 Subject: [PATCH 7/8] double response flow fix --- playground/demos/accountant_team/account_team2.py | 8 +++++--- swarms/structs/flow.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/playground/demos/accountant_team/account_team2.py b/playground/demos/accountant_team/account_team2.py index db3e6ed6..b39e91fc 100644 --- a/playground/demos/accountant_team/account_team2.py +++ b/playground/demos/accountant_team/account_team2.py @@ -19,10 +19,12 @@ openai_api_key = os.getenv("OPENAI_API_KEY") # Base llms llm1 = OpenAIChat( openai_api_key=openai_api_key, + max_tokens=5000, ) llm2 = Anthropic( anthropic_api_key=anthropic_api_key, + max_tokens=5000, ) @@ -59,16 +61,16 @@ print(pdf_text) fraud_detection_agent_output = doc_analyzer_agent.run( f"{fraud_detection_instructions}: {pdf_text}" ) -print(fraud_detection_agent_output) +# print(fraud_detection_agent_output) # Generate an actionable summary of the document summary_agent_output = summary_generator_agent.run( f"{summary_agent_instructions}: {fraud_detection_agent_output}" ) -print(summary_agent_output) +# print(summary_agent_output) # Provide decision making support to the accountant decision_making_support_agent_output = decision_making_support_agent.run( f"{decision_making_support_agent_instructions}: {summary_agent_output}" ) -print(decision_making_support_agent_output) \ No newline at end of file +# print(decision_making_support_agent_output) \ No newline at end of file diff --git a/swarms/structs/flow.py b/swarms/structs/flow.py index 8801a989..c3f36a82 100644 --- a/swarms/structs/flow.py +++ b/swarms/structs/flow.py @@ -457,7 +457,7 @@ class Flow: else: print(f"AI: {response}") history.append(f"AI: {response}") - print(response) + # print(response) break except Exception as e: logging.error(f"Error generating response: {e}") From b8c9ab04fe7f510c7c99da29f9d26270fe31ecb0 Mon Sep 17 00:00:00 2001 From: Kye Date: Sun, 19 Nov 2023 22:29:56 -0800 Subject: [PATCH 8/8] CLEAN UP: Structs folder of old workflow.py and nonlinearworkflow.py --- .../account_team2.py => account_team2.py | 6 +- pyproject.toml | 2 +- swarms/structs/task.py | 174 ------------------ swarms/structs/workflow.py | 84 --------- 4 files changed, 2 insertions(+), 264 deletions(-) rename playground/demos/accountant_team/account_team2.py => account_team2.py (92%) delete mode 100644 swarms/structs/task.py delete mode 100644 swarms/structs/workflow.py diff --git a/playground/demos/accountant_team/account_team2.py b/account_team2.py similarity index 92% rename from playground/demos/accountant_team/account_team2.py rename to account_team2.py index b39e91fc..d7842ee4 100644 --- a/playground/demos/accountant_team/account_team2.py +++ b/account_team2.py @@ -4,7 +4,6 @@ from swarms.models import Anthropic, OpenAIChat from swarms.prompts.accountant_swarm_prompts import ( DECISION_MAKING_PROMPT, DOC_ANALYZER_AGENT_PROMPT, - FRAUD_DETECTION_AGENT_PROMPT, SUMMARY_GENERATOR_AGENT_PROMPT, ) from swarms.structs import Flow @@ -61,16 +60,13 @@ print(pdf_text) fraud_detection_agent_output = doc_analyzer_agent.run( f"{fraud_detection_instructions}: {pdf_text}" ) -# print(fraud_detection_agent_output) # Generate an actionable summary of the document summary_agent_output = summary_generator_agent.run( f"{summary_agent_instructions}: {fraud_detection_agent_output}" ) -# print(summary_agent_output) # Provide decision making support to the accountant decision_making_support_agent_output = decision_making_support_agent.run( f"{decision_making_support_agent_instructions}: {summary_agent_output}" -) -# print(decision_making_support_agent_output) \ No newline at end of file +) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index c96f5119..d7fd64b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "swarms" -version = "2.3.7" +version = "2.3.9" description = "Swarms - Pytorch" license = "MIT" authors = ["Kye Gomez "] diff --git a/swarms/structs/task.py b/swarms/structs/task.py deleted file mode 100644 index 3d479c43..00000000 --- a/swarms/structs/task.py +++ /dev/null @@ -1,174 +0,0 @@ -# from __future__ import annotations - -# import json -# import pprint -# import uuid -# from abc import ABC, abstractmethod -# from enum import Enum -# from typing import Any, List, Optional, Union - -# from pydantic import BaseModel, Field, StrictStr -# # from swarms.artifacts.main import Artifact -# # from swarms.artifacts.error_artifact import ErrorArtifact - - -# class BaseTask(ABC): -# class State(Enum): -# PENDING = 1 -# EXECUTING = 2 -# FINISHED = 3 - -# def __init__(self): -# self.id: str = uuid.uuid4().hex -# self.state: BaseTask.State = self.State.PENDING -# self.parent_ids: List[str] = [] -# self.child_ids: List[str] = [] -# self.output = None -# self.structure = None - -# @property -# @abstractmethod -# def input(self) -> Any: -# pass - -# @property -# def parents(self) -> List[BaseTask]: -# return [self.structure.find_task(parent_id) for parent_id in self.parent_ids] - -# @property -# def children(self) -> List[BaseTask]: -# return [self.structure.find_task(child_id) for child_id in self.child_ids] - -# def __rshift__(self, child: BaseTask) -> BaseTask: -# return self.add_child(child) - -# def __lshift__(self, child: BaseTask) -> BaseTask: -# return self.add_parent(child) - -# def preprocess(self, structure) -> BaseTask: -# self.structure = structure -# return self - -# def add_child(self, child: BaseTask) -> BaseTask: -# if self.structure: -# child.structure = self.structure -# elif child.structure: -# self.structure = child.structure - -# if child not in self.structure.tasks: -# self.structure.tasks.append(child) - -# if self not in self.structure.tasks: -# self.structure.tasks.append(self) - -# if child.id not in self.child_ids: -# self.child_ids.append(child.id) - -# if self.id not in child.parent_ids: -# child.parent_ids.append(self.id) - -# return child - -# def add_parent(self, parent: BaseTask) -> BaseTask: -# if self.structure: -# parent.structure = self.structure -# elif parent.structure: -# self.structure = parent.structure - -# if parent not in self.structure.tasks: -# self.structure.tasks.append(parent) - -# if self not in self.structure.tasks: -# self.structure.tasks.append(self) - -# if parent.id not in self.parent_ids: -# self.parent_ids.append(parent.id) - -# if self.id not in parent.child_ids: -# parent.child_ids.append(self.id) - -# return parent - -# def is_pending(self) -> bool: -# return self.state == self.State.PENDING - -# def is_finished(self) -> bool: -# return self.state == self.State.FINISHED - -# def is_executing(self) -> bool: -# return self.state == self.State.EXECUTING - -# def before_run(self) -> None: -# pass - -# def after_run(self) -> None: -# pass - -# def execute(self) -> Optional[Union[Artifact, ErrorArtifact]]: -# try: -# self.state = self.State.EXECUTING -# self.before_run() -# self.output = self.run() -# self.after_run() -# except Exception as e: -# self.output = ErrorArtifact(str(e)) -# finally: -# self.state = self.State.FINISHED -# return self.output - -# def can_execute(self) -> bool: -# return self.state == self.State.PENDING and all( -# parent.is_finished() for parent in self.parents -# ) - -# def reset(self) -> BaseTask: -# self.state = self.State.PENDING -# self.output = None -# return self - -# @abstractmethod -# def run(self) -> Optional[Union[Artifact, ErrorArtifact]]: -# pass - - -# class Task(BaseModel): -# input: Optional[StrictStr] = Field(None, description="Input prompt for the task") -# additional_input: Optional[Any] = Field( -# None, description="Input parameters for the task. Any value is allowed" -# ) -# task_id: StrictStr = Field(..., description="ID of the task") - -# class Config: -# allow_population_by_field_name = True -# validate_assignment = True - -# def to_str(self) -> str: -# return pprint.pformat(self.dict(by_alias=True)) - -# def to_json(self) -> str: -# return json.dumps(self.dict(by_alias=True, exclude_none=True)) - -# @classmethod -# def from_json(cls, json_str: str) -> "Task": -# return cls.parse_raw(json_str) - -# def to_dict(self) -> dict: -# _dict = self.dict(by_alias=True, exclude_none=True) -# if self.artifacts: -# _dict["artifacts"] = [ -# artifact.dict(by_alias=True, exclude_none=True) -# for artifact in self.artifacts -# ] -# return _dict - -# @classmethod -# def from_dict(cls, obj: dict) -> "Task": -# if obj is None: -# return None -# if not isinstance(obj, dict): -# raise ValueError("Input must be a dictionary.") -# if "artifacts" in obj: -# obj["artifacts"] = [ -# Artifact.parse_obj(artifact) for artifact in obj["artifacts"] -# ] -# return cls.parse_obj(obj) diff --git a/swarms/structs/workflow.py b/swarms/structs/workflow.py deleted file mode 100644 index 31c95144..00000000 --- a/swarms/structs/workflow.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import annotations - -import uuid - -# from concurrent.futures import ThreadPoolExecutor -# from typing import Any, Dict, List, Optional -# # from swarms.structs.task import Task - - -# class Workflow: -# """ -# Workflows are ideal for prescriptive processes that need to be executed -# sequentially. -# They string together multiple tasks of varying types, and can use Short-Term Memory -# or pass specific arguments downstream. - -# Usage -# llm = LLM() -# workflow = Workflow(llm) - -# workflow.add("What's the weather in miami") -# workflow.add("Provide details for {{ parent_output }}") -# workflow.add("Summarize the above information: {{ parent_output}}) - -# workflow.run() - -# """ - -# def __init__(self, agent, parallel: bool = False): -# """__init__""" -# self.agent = agent -# self.tasks: List[Task] = [] -# self.parallel = parallel - -# def add(self, task: str) -> Task: -# """Add a task""" -# task = Task(task_id=uuid.uuid4().hex, input=task) - -# if self.last_task(): -# self.last_task().add_child(task) -# else: -# task.structure = self -# self.tasks.append(task) -# return task - -# def first_task(self) -> Optional[Task]: -# """Add first task""" -# return self.tasks[0] if self.tasks else None - -# def last_task(self) -> Optional[Task]: -# """Last task""" -# return self.tasks[-1] if self.tasks else None - -# def run(self, task: str) -> Task: -# """Run tasks""" -# self.add(task) - -# if self.parallel: -# with ThreadPoolExecutor() as executor: -# list(executor.map(self.__run_from_task, [self.first_task])) -# else: -# self.__run_from_task(self.first_task()) - -# return self.last_task() - -# def context(self, task: Task) -> Dict[str, Any]: -# """Context in tasks""" -# return { -# "parent_output": task.parents[0].output -# if task.parents and task.parents[0].output -# else None, -# "parent": task.parents[0] if task.parents else None, -# "child": task.children[0] if task.children else None, -# } - -# def __run_from_task(self, task: Optional[Task]) -> None: -# """Run from task""" -# if task is None: -# return -# else: -# if isinstance(task.execute(), Exception): -# return -# else: -# self.__run_from_task(next(iter(task.children), None))