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

fix custom messenger interface #206

Merged
merged 17 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 6 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
17 changes: 4 additions & 13 deletions tests/pipeline/test_tutorials.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from tests.test_utils import get_path_from_tests_to_current_dir
from dff.utils.testing import check_happy_path, HAPPY_PATH
from dff.script import Message

dot_path_to_addon = get_path_from_tests_to_current_dir(__file__, separator=".")

Expand All @@ -19,22 +18,14 @@
"4_groups_and_conditions_full",
"5_asynchronous_groups_and_services_basic",
"5_asynchronous_groups_and_services_full",
"6_custom_messenger_interface",
"7_extra_handlers_basic",
"7_extra_handlers_full",
"8_extra_handlers_and_extensions",
"6_extra_handlers_basic",
"6_extra_handlers_full",
"7_extra_handlers_and_extensions",
],
)
def test_tutorials(tutorial_module_name: str):
try:
tutorial_module = importlib.import_module(f"tutorials.{dot_path_to_addon}.{tutorial_module_name}")
except ModuleNotFoundError as e:
pytest.skip(f"dependencies unavailable: {e.msg}")
if tutorial_module_name == "6_custom_messenger_interface":
happy_path = tuple(
(req, Message(misc={"webpage": tutorial_module.construct_webpage_by_response(res.text)}))
for req, res in HAPPY_PATH
)
check_happy_path(tutorial_module.pipeline, happy_path)
else:
check_happy_path(tutorial_module.pipeline, HAPPY_PATH)
check_happy_path(tutorial_module.pipeline, HAPPY_PATH)
50 changes: 47 additions & 3 deletions tutorials/messengers/web_api_interface/1_fastapi.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# %% [markdown]
"""
# Web API: 1. FastAPI
# Web API: 2. FastAPI

This tutorial shows how to create an API for DFF using FastAPI.

Expand All @@ -10,6 +10,7 @@
# %pip install dff uvicorn fastapi

# %%
from dff.messengers.common.interface import CallbackMessengerInterface
from dff.script import Message
from dff.pipeline import Pipeline
from dff.utils.testing import TOY_SCRIPT_ARGS, is_interactive_mode
Expand All @@ -18,9 +19,51 @@
from pydantic import BaseModel
from fastapi import FastAPI

# %% [markdown]
"""
Messenger interfaces establish communication between users and the pipeline.
They manage message channel initialization and termination
as well as pipeline execution on every user request.
There are two built-in messenger interface types (that may be overridden):

* `PollingMessengerInterface` - Starts polling for user requests
in a loop upon initialization,
it has following methods:
* `_request()` - Method that is executed in a loop,
should return list of tuples: (user request, unique dialog id).
* `_respond(responses)` - Method that is executed in a loop
after all user requests processing,
accepts list of dialog `Contexts`.
* `_on_exception(e)` - Method that is called on
exception that happens in the loop,
should catch the exception
(it is also called on pipeline termination).
* `connect(pipeline_runner, loop, timeout)` -
Method that is called on connection to message channel,
accepts pipeline_runner (a callback, running pipeline).
* loop - A function to be called on each loop
execution (should return True to continue polling).
* timeout - Time in seconds to wait between loop executions.

* `CallbackMessengerInterface` - Creates message channel
and provides a callback for pipeline execution,
it has following method:
* `on_request(request, ctx_id)` - Method that should be called each time
user provides new input to pipeline,
returns dialog Context.

`CLIMessengerInterface` is also
a messenger interface that overrides `PollingMessengerInterface` and
provides default message channel between pipeline and console/file IO.

Here the default `CallbackMessengerInterface` is used to setup
communication between the pipeline on the server side and the messenger client.
"""

# %%
pipeline = Pipeline.from_script(*TOY_SCRIPT_ARGS)
messenger_interface = CallbackMessengerInterface()
# CallbackMessengerInterface instantiating the dedicated messenger interface
pipeline = Pipeline.from_script(*TOY_SCRIPT_ARGS, messenger_interface=messenger_interface)


# %%
Expand All @@ -37,13 +80,14 @@ async def respond(
user_id: str,
user_message: Message,
):
context = await pipeline._run_pipeline(user_message, user_id) # run in async
context = messenger_interface.on_request(user_message, user_id)
return {"user_id": user_id, "response": context.last_response}


# %%
if __name__ == "__main__":
if is_interactive_mode(): # do not run this during doc building
pipeline.run()
uvicorn.run(
app,
host="127.0.0.1",
Expand Down
13 changes: 7 additions & 6 deletions tutorials/messengers/web_api_interface/2_websocket_chat.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# %% [markdown]
"""
# Web API: 2. WebSocket Chat
# Web API: 3. WebSocket Chat

This tutorial shows how to create a Web chat on FastAPI using websockets.

Expand All @@ -19,19 +19,19 @@
# %pip install dff uvicorn fastapi

# %%
from dff.messengers.common.interface import CallbackMessengerInterface
from dff.script import Message
from dff.pipeline import Pipeline
from dff.utils.testing import TOY_SCRIPT, is_interactive_mode
from dff.utils.testing import TOY_SCRIPT_ARGS, is_interactive_mode

import uvicorn
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse


# %%
pipeline = Pipeline.from_script(
TOY_SCRIPT, ("greeting_flow", "start_node"), ("greeting_flow", "fallback_node")
)
messenger_interface = CallbackMessengerInterface()
pipeline = Pipeline.from_script(*TOY_SCRIPT_ARGS, messenger_interface=messenger_interface)


# %%
Expand Down Expand Up @@ -86,7 +86,7 @@ async def websocket_endpoint(websocket: WebSocket, client_id: int):
data = await websocket.receive_text()
await websocket.send_text(f"User: {data}")
request = Message(text=data)
context = await pipeline._run_pipeline(request, client_id)
context = messenger_interface.on_request(request, client_id)
response = context.last_response.text
if response is not None:
await websocket.send_text(f"Bot: {response}")
Expand All @@ -99,6 +99,7 @@ async def websocket_endpoint(websocket: WebSocket, client_id: int):
# %%
if __name__ == "__main__":
if is_interactive_mode(): # do not run this during doc building
pipeline.run()
uvicorn.run(
app,
host="127.0.0.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# %% [markdown]
"""
# Web API: 3. Load testing with Locust
# Web API: 4. Load testing with Locust

This tutorial shows how to use an API endpoint created in the FastAPI tutorial in load testing.
"""
Expand Down
2 changes: 1 addition & 1 deletion tutorials/messengers/web_api_interface/4_streamlit_chat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# %% [markdown]
# # Web API: 4. Streamlit chat interface
# # Web API: 5. Streamlit chat interface
#
# This tutorial shows how to use an API endpoint created in the FastAPI tutorial
# in a Streamlit chat.
Expand Down
155 changes: 0 additions & 155 deletions tutorials/pipeline/6_custom_messenger_interface.py

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# %% [markdown]
"""
# 7. Extra Handlers (basic)
# 6. Extra Handlers (basic)

The following tutorial shows extra handlers possibilities and use cases.
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# %% [markdown]
"""
# 7. Extra Handlers (full)
# 6. Extra Handlers (full)

The following tutorial shows extra handlers possibilities and use cases.
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# %% [markdown]
"""
# 8. Extra Handlers and Extensions
# 7. Extra Handlers and Extensions

The following tutorial shows how pipeline can be extended
by global extra handlers and custom functions.
Expand Down
2 changes: 1 addition & 1 deletion tutorials/stats/2_pipeline_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# 2. Pipeline Integration

In the DFF ecosystem, extractor functions act as regular extra handlers (
[see the pipeline module documentation](%doclink(tutorial,pipeline.7_extra_handlers_basic))
[see the pipeline module documentation](%doclink(tutorial,pipeline.6_extra_handlers_basic))
).
Hence, you can decorate any part of your pipeline, including services,
service groups and the pipeline as a whole, to obtain the statistics
Expand Down