Skip to content

Commit

Permalink
Merge branch 'dev' into french/240423/text-to-audio
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewfrench authored May 14, 2024
2 parents 7b85d66 + c39ad53 commit cfa71d8
Show file tree
Hide file tree
Showing 74 changed files with 1,650 additions and 249 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/docs-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ jobs:
GOOGLE_AUTH_URI: ${{ secrets.INTEG_GOOGLE_AUTH_URI }}
GOOGLE_TOKEN_URI: ${{ secrets.INTEG_GOOGLE_TOKEN_URI }}
GOOGLE_AUTH_PROVIDER_X509_CERT_URL: ${{ secrets.INTEG_GOOGLE_AUTH_PROVIDER_X509_CERT_URL }}
GRIPTAPE_CLOUD_API_KEY: ${{ secrets.INTEG_GRIPTAPE_CLOUD_API_KEY }}
GRIPTAPE_CLOUD_STRUCTURE_ID: ${{ secrets.INTEG_GRIPTAPE_CLOUD_STRUCTURE_ID }}
GRIPTAPE_CLOUD_BASE_URL: ${{ secrets.INTEG_GRIPTAPE_CLOUD_BASE_URL }}
OPENWEATHER_API_KEY: ${{ secrets.INTEG_OPENWEATHER_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.INTEG_ANTHROPIC_API_KEY }}
SAGEMAKER_LLAMA_ENDPOINT_NAME: ${{ secrets.INTEG_LLAMA_ENDPOINT_NAME }}
Expand Down Expand Up @@ -92,6 +95,11 @@ jobs:
POSTGRES_HOST: ${{ secrets.INTEG_POSTGRES_HOST }}
POSTGRES_PORT: ${{ secrets.INTEG_POSTGRES_PORT }}
VOYAGE_API_KEY: ${{ secrets.INTEG_VOYAGE_API_KEY }}
WEBHOOK_URL: ${{ secrets.INTEG_WEBHOOK_URL }}
AMAZON_SQS_QUEUE_URL: ${{ secrets.INTEG_AMAZON_SQS_QUEUE_URL }}
GT_CLOUD_STRUCTURE_RUN_ID: ${{ secrets.INTEG_GT_CLOUD_STRUCTURE_RUN_ID }}
AWS_IOT_CORE_ENDPOINT: ${{ secrets.INTEG_AWS_IOT_CORE_ENDPOINT }}
AWS_IOT_CORE_TOPIC: ${{ secrets.INTEG_AWS_IOT_CORE_TOPIC }}
services:
postgres:
image: ankane/pgvector:v0.5.0
Expand Down
32 changes: 25 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Changed
- Default behavior of OpenAiStructureConfig to utilize `gpt-4o` for prompt_driver.

## [0.25.1] - 2024-05-09
### Added
- Optional event batching on Event Listener Drivers.
- `id` field to all events.

### Changed
- Default behavior of Event Listener Drivers to batch events.

## [0.25.0] - 2024-05-06

### Added
- `list_files_from_disk` activity to `FileManager` Tool.
- Support for Drivers in `EventListener`.
- `AmazonSqsEventListenerDriver` for sending events to an Amazon SQS queue.
- `AwsIotCoreEventListenerDriver` for sending events to a topic on AWS IoT Core.
- `GriptapeCloudEventListenerDriver` for sending events to Griptape Cloud.
- `WebhookEventListenerDriver` for sending events to a webhook.
- `LocalEventListenerDriver` for sending events to a callback function.
- `BaseFileManagerDriver` to abstract file management operations.
- `LocalFileManagerDriver` for managing files on the local file system.
- Added optional `BaseLoader.encoding` field.
- Optional `BaseLoader.encoding` field.
- `BlobLoader` for loading arbitrary binary data as a `BlobArtifact`.
- `model` field to `StartPromptEvent` and `FinishPromptEvent`.
- `input_task_input` and `input_task_output` fields to `StartStructureRunEvent`.
- `output_task_input` and `output_task_output` fields to `FinishStructureRunEvent`.
- `AmazonS3FileManagerDriver` for managing files on Amazon S3.
- `MediaArtifact` as a base class for `ImageArtifact` and future media Artifacts.
- Optional `exception` field to `ErrorArtifact`.
- `StructureRunClient` for running other Structures via a Tool.
- `StructureRunTask` for running Structures as a Task from within another Structure.
- `GriptapeCloudStructureRunDriver` for running Structures in Griptape Cloud.
- `LocalStructureRunDriver` for running Structures in the same run-time environment as the code that is running the Structure.

### Changed
- **BREAKING**: Secret fields (ex: api_key) removed from serialized Drivers.
Expand All @@ -32,11 +48,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **BREAKING**: `PdfLoader` no longer accepts `str` file content, `Path` file paths or `IO` objects as sources. Instead, it will only accept the content of the PDF file as a `bytes` object.
- **BREAKING**: `TextLoader` no longer accepts `Path` file paths as a source. It will now accept the content of the text file as a `str` or `bytes` object.
- **BREAKING**: `FileManager.default_loader` is now `None` by default.
- **BREAKING**: Replaced `EventListener.handler` with `EventListener.driver` and `LocalEventListenerDriver`.
- Improved RAG performance in `VectorQueryEngine`.
- **BREAKING** Bumped `pinecone` from `^2` to `^3`.
- **BREAKING**: Removed `workdir`, `loaders`, `default_loader`, and `save_file_encoding` fields from `FileManager` and added `file_manager_driver`.
- **BREADKING**: Removed `mime_type` field from `ImageArtifact`. `mime_type` is now a property constructed using the Artifact type and `format` field.
- **BREAKING**: Removed `mime_type` field from `ImageArtifact`. `mime_type` is now a property constructed using the Artifact type and `format` field.
- Improved RAG performance in `VectorQueryEngine`.
- Moved [Griptape Docs](https://github.com/griptape-ai/griptape-docs) to this repository.
- Updated `EventListener.handler`'s behavior so that the return value will be passed to the `EventListenerDriver.try_publish_event_payload`'s `event_payload` parameter.

### Fixed
- Type hint for parameter `azure_ad_token_provider` on Azure OpenAI drivers to `Optional[Callable[[], str]]`.
Expand Down Expand Up @@ -122,13 +139,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `ImageQueryTask` and `ImageQueryEngine`.

### Fixed
- `BedrockStableDiffusionImageGenerationModelDriver` request parameters for SDXLv1.
- `BedrockStableDiffusionImageGenerationModelDriver` request parameters for SDXLv1 (`stability.stable-diffusion-xl-v1`).
- `BedrockStableDiffusionImageGenerationModelDriver` correctly handles the CONTENT_FILTERED response case.

### Changed
- **BREAKING**: Make `index_name` on `MongoDbAtlasVectorStoreDriver` a required field.
- **BREAKING**: Remove `create_index()` from `MarqoVectorStoreDriver`, `OpenSearchVectorStoreDriver`, `PineconeVectorStoreDriver`, `RedisVectorStoreDriver`.
- **BREAKING**: `ImageLoader().load()` now accepts image bytes instead of a file path.
- **BREAKING**: Request parameters for `BedrockStableDiffusionImageGenerationModelDriver` have been updated for `stability.stable-diffusion-xl-v1`. Use this over the now deprecated `stability.stable-diffusion-xl-v0`.
- Deprecated `Structure.prompt_driver` in favor of `Structure.config.global_drivers.prompt_driver`.
- Deprecated `Structure.embedding_driver` in favor of `Structure.config.global_drivers.embedding_driver`.
- Deprecated `Structure.stream` in favor of `Structure.config.global_drivers.prompt_driver.stream`.
Expand All @@ -147,7 +165,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.22.2] - 2024-01-18

### Fixed
- `ToolkitTask`'s user subtask prompt occassionally causing a loop with Chain of Thought.
- `ToolkitTask`'s user subtask prompt occasionally causing a loop with Chain of Thought.

### Security
- Updated stale dependencies [CVE-2023-50447, CVE-2024-22195, and CVE-2023-36464]
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ Tools provide capabilities for LLMs to interact with data and services. Griptape

Drivers facilitate interactions with external resources and services:

- 🔢 **Prompt and Embedding Drivers** generate vector embeddings from textual inputs.
- 🗣️ **Prompt Drivers** manage textual interactions with LLMs.
- 🔢 **Embedding Drivers** generate vector embeddings from textual inputs.
- 💾 **Vector Store Drivers** manage the storage and retrieval of embeddings.
- 🎨 **Image Generation Drivers** create images from text descriptions.
- 🔎 **Image Query Drivers** query images from text queries.
Expand Down
191 changes: 191 additions & 0 deletions docs/examples/multi-agent-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
In this example we implement a multi-agent Workflow. We have a single "Researcher" Agent that conducts research on a topic, and then fans out to multiple "Writer" Agents to write blog posts based on the research.

By splitting up our workloads across multiple Structures, we can parallelize the work and leverage the strengths of each Agent. The Researcher can focus on gathering data and insights, while the Writers can focus on crafting engaging narratives.
Additionally, this architecture opens us up to using services such as [Griptape Cloud](https://www.griptape.ai/cloud) to have each Agent run on a separate machine, allowing us to scale our Workflow as needed 🤯.


```python
import os

from griptape.drivers import WebhookEventListenerDriver, LocalStructureRunDriver
from griptape.events import EventListener, FinishStructureRunEvent
from griptape.rules import Rule, Ruleset
from griptape.structures import Agent, Workflow
from griptape.tasks import PromptTask, StructureRunTask
from griptape.tools import (
TaskMemoryClient,
WebScraper,
WebSearch,
)

WRITERS = [
{
"role": "Travel Adventure Blogger",
"goal": "Inspire wanderlust with stories of hidden gems and exotic locales",
"backstory": "With a passport full of stamps, you bring distant cultures and breathtaking scenes to life through vivid storytelling and personal anecdotes.",
},
{
"role": "Lifestyle Freelance Writer",
"goal": "Share practical advice on living a balanced and stylish life",
"backstory": "From the latest trends in home decor to tips for wellness, your articles help readers create a life that feels both aspirational and attainable.",
},
]


def build_researcher():
"""Builds a Researcher Structure."""
researcher = Agent(
id="researcher",
tools=[
WebSearch(
google_api_key=os.environ["GOOGLE_API_KEY"],
google_api_search_id=os.environ["GOOGLE_API_SEARCH_ID"],
off_prompt=False,
),
WebScraper(
off_prompt=True,
),
TaskMemoryClient(off_prompt=False),
],
rulesets=[
Ruleset(
name="Position",
rules=[
Rule(
value="Lead Research Analyst",
)
],
),
Ruleset(
name="Objective",
rules=[
Rule(
value="Discover innovative advancements in artificial intelligence and data analytics",
)
],
),
Ruleset(
name="Background",
rules=[
Rule(
value="""You are part of a prominent technology research institute.
Your speciality is spotting new trends.
You excel at analyzing intricate data and delivering practical insights."""
)
],
),
Ruleset(
name="Desired Outcome",
rules=[
Rule(
value="Comprehensive analysis report in list format",
)
],
),
],
)

return researcher


def build_writer(role: str, goal: str, backstory: str):
"""Builds a Writer Structure.
Args:
role: The role of the writer.
goal: The goal of the writer.
backstory: The backstory of the writer.
"""
writer = Agent(
id=role.lower().replace(" ", "_"),
event_listeners=[
EventListener(
event_types=[FinishStructureRunEvent],
driver=WebhookEventListenerDriver(
webhook_url=os.environ["WEBHOOK_URL"],
),
)
],
rulesets=[
Ruleset(
name="Position",
rules=[
Rule(
value=role,
)
],
),
Ruleset(
name="Objective",
rules=[
Rule(
value=goal,
)
],
),
Ruleset(
name="Backstory",
rules=[Rule(value=backstory)],
),
Ruleset(
name="Desired Outcome",
rules=[
Rule(
value="Full blog post of at least 4 paragraphs",
)
],
),
],
)

return writer


if __name__ == "__main__":
# Build the team
team = Workflow()
research_task = team.add_task(
StructureRunTask(
(
"""Perform a detailed examination of the newest developments in AI as of 2024.
Pinpoint major trends, breakthroughs, and their implications for various industries.""",
),
id="research",
driver=LocalStructureRunDriver(
structure_factory_fn=build_researcher,
),
),
)
end_task = team.add_task(
PromptTask(
'State "All Done!"',
)
)
team.insert_tasks(
research_task,
[
StructureRunTask(
(
"""Using insights provided, develop an engaging blog
post that highlights the most significant AI advancements.
Your post should be informative yet accessible, catering to a tech-savvy audience.
Make it sound cool, avoid complex words so it doesn't sound like AI.
Insights:
{{ parent_outputs["research"] }}""",
),
driver=LocalStructureRunDriver(
structure_factory_fn=lambda: build_writer(
role=writer["role"],
goal=writer["goal"],
backstory=writer["backstory"],
)
),
)
for writer in WRITERS
],
end_task,
)

team.run()
```
1 change: 1 addition & 0 deletions docs/griptape-cloud/api/api-reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Content overridden by Swagger Plugin
3 changes: 3 additions & 0 deletions docs/griptape-cloud/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Griptape Cloud

Griptape Cloud is a managed platform for running AI-powered agents, pipelines, and workflows.
29 changes: 28 additions & 1 deletion docs/griptape-framework/data/loaders.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@ Inherits from the [TextLoader](../../reference/griptape/loaders/text_loader.md)

```python
from griptape.loaders import PdfLoader
from griptape.utils import load_files, load_file
import urllib.request

urllib.request.urlretrieve("https://arxiv.org/pdf/1706.03762.pdf", "attention.pdf")

# Load a single PDF file
with open("attention.pdf", "rb") as f:
PdfLoader().load(f.read())
# You can also use the load_file utility function
PdfLoader().load(load_file("attention.pdf"))

urllib.request.urlretrieve("https://arxiv.org/pdf/1706.03762.pdf", "CoT.pdf")

# Load multiple PDF files
with open("attention.pdf", "rb") as attention, open("CoT.pdf", "rb") as cot:
PdfLoader().load_collection([attention.read(), cot.read()])
# You can also use the load_files utility function
PdfLoader().load_collection(list(load_files(["attention.pdf", "CoT.pdf"]).values()))
```

## Sql Loader
Expand Down Expand Up @@ -53,12 +60,19 @@ Can be used to load CSV files into [CsvRowArtifact](../../reference/griptape/art

```python
from griptape.loaders import CsvLoader
from griptape.utils import load_file, load_files

# Load a single CSV file
with open("tests/resources/cities.csv", "r") as f:
CsvLoader().load(f.read())
# You can also use the load_file utility function
CsvLoader().load(load_file("tests/resources/cities.csv"))

# Load multiple CSV files
with open("tests/resources/cities.csv", "r") as cities, open("tests/resources/addresses.csv", "r") as addresses:
CsvLoader().load_collection([cities.read(), addresses.read()])
# You can also use the load_files utility function
CsvLoader().load_collection(list(load_files(["tests/resources/cities.csv", "tests/resources/addresses.csv"]).values()))
```


Expand Down Expand Up @@ -140,19 +154,32 @@ The Image Loader is used to load an image as an [ImageArtifact](./artifacts.md#i

```python
from griptape.loaders import ImageLoader
from griptape.utils import load_file

# Load an image from disk
with open("tests/resources/mountain.png", "rb") as f:
disk_image_artifact = ImageLoader().load(f.read())
# You can also use the load_file utility function
ImageLoader().load(load_file("tests/resources/mountain.png"))
```

By default, the Image Loader will load images in their native format, but not all models work on all formats. To normalize the format of Artifacts returned by the Loader, set the `format` field.

```python
from griptape.loaders import ImageLoader
from griptape.utils import load_files, load_file

# Image data in artifact will be in BMP format.
# Load a single image in BMP format
with open("tests/resources/mountain.png", "rb") as f:
image_artifact_jpeg = ImageLoader(format="bmp").load(f.read())
# You can also use the load_file utility function
ImageLoader(format="bmp").load(load_file("tests/resources/mountain.png"))

# Load multiple images in BMP format
with open("tests/resources/mountain.png", "rb") as mountain, open("tests/resources/cow.png", "rb") as cow:
ImageLoader().load_collection([mountain.read(), cow.read()])
# You can also use the load_files utility function
ImageLoader().load_collection(list(load_files(["tests/resources/mountain.png", "tests/resources/cow.png"]).values()))
```


Expand Down
Loading

0 comments on commit cfa71d8

Please sign in to comment.