Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/pusher event driver #821

Merged
merged 11 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/docs-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ jobs:
AWS_IOT_CORE_ENDPOINT: ${{ secrets.INTEG_AWS_IOT_CORE_ENDPOINT }}
AWS_IOT_CORE_TOPIC: ${{ secrets.INTEG_AWS_IOT_CORE_TOPIC }}
ELEVEN_LABS_API_KEY: ${{ secrets.INTEG_ELEVEN_LABS_API_KEY }}
PUSHER_APP_ID: ${{ secrets.INTEG_PUSHER_APP_ID }}
PUSHER_KEY: ${{ secrets.INTEG_PUSHER_KEY }}
PUSHER_SECRET: ${{ secrets.INTEG_PUSHER_SECRET }}
PUSHER_CLUSTER: ${{ secretes.INTEG_PUSHER_CLUSTER }}
services:
postgres:
image: ankane/pgvector:v0.5.0
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `AudioTranscriptionTask` and `AudioTranscriptionClient` for transcribing audio content in Structures.
- `OpenAiAudioTranscriptionDriver` for integration with OpenAI's speech-to-text models, including Whisper.
- Parameter `env` to `BaseStructureRunDriver` to set environment variables for a Structure Run.
- `PusherEventListenerDriver` to enable sending of framework events over a Pusher WebSocket.

### Changed
- **BREAKING**: Updated OpenAI-based image query drivers to remove Vision from the name.
Expand Down
35 changes: 35 additions & 0 deletions docs/griptape-framework/drivers/event-listener-drivers.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,39 @@ agent = Agent(

agent.run("Analyze the pros and cons of remote work vs. office work")
```
### Pusher Event Listener Driver

!!! info
This driver requires the `drivers-event-listener-pusher` [extra](../index.md#extras).

The [PusherEventListenerDriver](../../reference/griptape/drivers/event_listener/pusher_event_listener_driver.md) sends Events to [Pusher](https://pusher.com).

```python
import os
from griptape.drivers import PusherEventListenerDriver
from griptape.events import (
EventListener,
FinishStructureRunEvent
)
from griptape.structures import Agent

agent = Agent(
event_listeners=[
EventListener(
event_types=[FinishStructureRunEvent],
driver=PusherEventListenerDriver(
batched=False,
app_id=os.environ["PUSHER_APP_ID"],
key=os.environ["PUSHER_KEY"],
secret=os.environ["PUSHER_SECRET"],
cluster=os.environ["PUSHER_CLUSTER"],
channel='my-channel',
event_name='my-event'
),
),
],
)

agent.run("Analyze the pros and cons of remote work vs. office work")

```
2 changes: 2 additions & 0 deletions griptape/drivers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
from .event_listener.webhook_event_listener_driver import WebhookEventListenerDriver
from .event_listener.aws_iot_core_event_listener_driver import AwsIotCoreEventListenerDriver
from .event_listener.griptape_cloud_event_listener_driver import GriptapeCloudEventListenerDriver
from .event_listener.pusher_event_listener_driver import PusherEventListenerDriver

from .file_manager.base_file_manager_driver import BaseFileManagerDriver
from .file_manager.local_file_manager_driver import LocalFileManagerDriver
Expand Down Expand Up @@ -193,6 +194,7 @@
"WebhookEventListenerDriver",
"AwsIotCoreEventListenerDriver",
"GriptapeCloudEventListenerDriver",
"PusherEventListenerDriver",
"BaseFileManagerDriver",
"LocalFileManagerDriver",
"AmazonS3FileManagerDriver",
Expand Down
39 changes: 39 additions & 0 deletions griptape/drivers/event_listener/pusher_event_listener_driver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from __future__ import annotations

from typing import TYPE_CHECKING
from attrs import define, field, Factory
from griptape.drivers import BaseEventListenerDriver
from griptape.utils import import_optional_dependency

if TYPE_CHECKING:
from pusher import Pusher


@define
class PusherEventListenerDriver(BaseEventListenerDriver):
app_id: str = field(kw_only=True)
key: str = field(kw_only=True)
secret: str = field(kw_only=True)
cluster: str = field(kw_only=True)
channel: str = field(kw_only=True)
event_name: str = field(kw_only=True)
pusher_client: Pusher = field(
default=Factory(
lambda self: import_optional_dependency("pusher").Pusher(
app_id=self.app_id, key=self.key, secret=self.secret, cluster=self.cluster, ssl=True
),
takes_self=True,
),
kw_only=True,
)

def try_publish_event_payload_batch(self, event_payload_batch: list[dict]) -> None:
data = [
{"channel": self.channel, "name": self.event_name, "data": event_payload}
for event_payload in event_payload_batch
]

self.pusher_client.trigger_batch(data)

def try_publish_event_payload(self, event_payload: dict) -> None:
self.pusher_client.trigger(channels=self.channel, event_name=self.event_name, data=event_payload)
73 changes: 70 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ markdownify = {version = "^0.11.6", optional = true}
voyageai = {version = "^0.2.1", optional = true}
elevenlabs = {version = "^1.1.2", optional = true}
torch = {version = "^2.3.0", optional = true}
pusher = {version = "^3.3.2", optional = true}

# loaders
pandas = {version = "^1.3", optional = true}
Expand Down Expand Up @@ -96,6 +97,7 @@ drivers-web-scraper-markdownify = ["playwright", "beautifulsoup4", "markdownify"

drivers-event-listener-amazon-sqs = ["boto3"]
drivers-event-listener-amazon-iot = ["boto3"]
drivers-event-listener-pusher = ["pusher"]

loaders-dataframe = ["pandas"]
loaders-pdf = ["pypdf"]
Expand Down Expand Up @@ -128,6 +130,7 @@ all = [
"voyageai",
"elevenlabs",
"torch",
"pusher",

# loaders
"pandas",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from pytest import fixture
from tests.mocks.mock_event import MockEvent
from griptape.drivers import PusherEventListenerDriver
from unittest.mock import Mock


class TestPusherEventListenerDriver:
@fixture(autouse=True)
def mock_post(self, mocker):
mock_pusher_client = mocker.patch("pusher.Pusher")
mock_pusher_client.return_value.trigger.return_value = Mock()
mock_pusher_client.return_value.trigger_batch.return_value = Mock()

return mock_pusher_client

@fixture()
def driver(self):
return PusherEventListenerDriver(
app_id="test-app-id",
key="test-key",
secret="test-secret",
cluster="test-cluster",
channel="test-channel",
event_name="test-event",
)

def test_init(self, driver):
assert driver

def test_try_publish_event_payload(self, driver):
driver.try_publish_event_payload(MockEvent().to_dict())

assert driver.pusher_client.trigger.called_with(
channels="test-channel", event_name="test-event", data=MockEvent().to_dict()
)

def test_try_publish_event_payload_batch(self, driver):
driver.try_publish_event_payload_batch([MockEvent().to_dict() for _ in range(3)])

assert driver.pusher_client.trigger_batch.called_with(
[{"channel": "test-channel", "name": "test-event", "data": MockEvent().to_dict()} for _ in range(3)]
)
Loading