From d26a65b125a0d015f7dd17a084d4ea6e822a33a5 Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Fri, 1 Sep 2023 16:40:06 +0300 Subject: [PATCH 01/15] update basic conceptions --- docs/source/user_guides/basic_conceptions.rst | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 9f81a8610..d4ad77225 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -301,3 +301,154 @@ Happy building! .. _tutorial on pre-response processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.7_pre_response_processing.html .. _tutorial on pre-transition processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.9_pre_transitions_processing.html .. _tutorial on script MISC: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.8_misc.html + + +Basic Concepts +-------------- + +============ +Introduction +============ + +The Dialog Flow Framework (DFF) is a modern tool for designing conversational services. + +DFF helps users create conversational services by defining a specialized dialog graph that dictates the behavior of the dialog service. +This dialog graph represents the dialog script that guides the conversation between the chat-bot and the user and covers one or several scenarios. + +This tutorial walks you through the process of creating and maintaining a service with the help of DFF. + + +=========================================== +Creating Conversational Services with DFF +=========================================== + +Installation +------------ + +To get started with DFF, you need to install its core dependencies, which can be done using the following command: + + .. code-block:: shell + + pip3 install dff + + +Defining Dialogue Goals and User Scenarios +------------------------------------------ + +To create a conversational service using Dialog Flow Framework (DFF), you start by defining the overall dialogue goal +and breaking down the dialogue into scenarios based on the user needs that you intend to cover. +DFF leverages a specialized Domain-Specific Language (DSL) that makes it easy to break down the dialog into the parts +that you lay down at this stage. + +Creating Dialogue Flows for User Scenarios +------------------------------------------- + +Once you have DFF installed, you can begin creating dialogue flows for various user scenarios. Let's consider an example of a simple chat-bot that plays a virtual ping-pong game with users and handles exceptions. Here's a snippet of the chat-bot graph: + +.. code-block:: python + + from dff.pipeline import Pipeline + from dff.script import TRANSITIONS, RESPONSE, Message + import dff.script.conditions as cnd + + ping_pong_script = { + "ping_pong_flow": { + "start_node": { + RESPONSE: Message(), + TRANSITIONS: { + "greeting_node": cnd.exact_match(Message(text="Hello!")), + }, + }, + "greeting_node": { + RESPONSE: Message(text="Hi! Let's play ping-pong!"), + TRANSITIONS: { + "response_node": cnd.exact_match(Message(text="Ping!")), + }, + }, + "response_node": { + RESPONSE: Message(text="Pong!"), + TRANSITIONS: { + "response_node": cnd.exact_match(Message(text="Ping!")), + }, + }, + "fallback_node": { + RESPONSE: Message(text="That was against the rules!"), + TRANSITIONS: { + "greeting_node": cnd.true(), + }, + }, + }, + } + + pipeline = Pipeline.from_script( + ping_pong_script, + start_label=("ping_pong_flow", "start_node"), + fallback_label=("ping_pong_flow", "fallback_node"), + ) + +In this code, we define a script with a single dialogue flow that emulates a ping-pong game. +Likewise, if additional scenarios need to be covered, additional flow objects can be embedded into the same script object. + +The flow consists of several nodes, including a start node, a greeting node, a response node, and a fallback node. +Each node has a defined response and transitions based on user input. + +Request Handler Definition +-------------------------- + +The request handler definition in DFF involves deciding how user requests will be processed to extract additional parameters. This may include writing code to execute SQL queries or accessing an external API. For example, if the user wants to know the schedule, parameters could be the date and location. After retrieving data from the database or API, you need to process it and ensure it meets expectations. If the data is incorrect or missing, provide error handling logic. + +Generating a Response to the User +---------------------------------- + +Creating a response to the user in DFF involves creating a text or multimedia response from the bot that will be delivered to the user. This response may include data from a database or API, as shown in the previous code example. + +Handling Fallbacks and Errors +------------------------------- + +In DFF, you should provide handling for situations where the user makes requests that the bot cannot answer. Create friendly error messages and, if possible, suggest alternative options. This ensures a smoother user experience even when the bot encounters unexpected inputs. + +Testing and Debugging +---------------------- + +Periodically testing the intent is crucial to ensure it works correctly. You should also be prepared to debug the code and dialogue logic if problems are discovered during testing. This step is essential to iron out any issues and make the bot more reliable. + +Monitoring and Analytics +------------------------- + +Setting up bot performance monitoring and usage analytics is essential to monitor its operation and identify potential issues. Monitoring helps you understand how users are interacting with the bot and whether any improvements are needed. + +Iterative Improvement +---------------------- + +To continually enhance your chat-bot's performance, monitor user feedback and analyze data on bot usage. Gradually improve the dialogue logic and functionality based on the data received. This iterative approach ensures that the bot becomes more effective over time. + +Data Protection +---------------- + +Data protection is a critical consideration in bot development, especially when handling sensitive information. +The DFF framework helps ensure the safety of your application by storing the history and other user data present +in the `Context` object under unique ids and abstracting the storage logic away from the user interface. +As a result, it offers the basic level of data protection making it impossible to gain unlawful access to personal information. + +Documentation +-------------- + +Creating documentation is essential for teamwork and future bot maintenance. +Document how the intent works, its parameters, and expected outcomes. +This documentation serves as a reference for developers and stakeholders involved in the project. + +Scaling +------- + +If your bot becomes popular and requires scaling, consider scalability during development. +Scalability ensures that the bot can handle a growing user base without performance issues. +While having only one application instance will suffice in most cases, there are many ways +how you can adapt the application to a high load environment. + +* With the database connection support that DFF offers out of the box, DFF projects +can be easily scaled through sharing the same database between multiple application instances. +However, using an external database is required due to the fact that this is the only kind of storage +that can be efficiently shared between processes. +* Likewise, using multiple database instances to ensure the availability of data is also an option. +* The structure of the `Context` object makes it easy to shard the data storing different subsets +of data across multiple database instances. From b8304558e25fbad8437f9abc5bee926d5e9cfdc9 Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Mon, 4 Sep 2023 16:20:54 +0300 Subject: [PATCH 02/15] Update basic concepts tutorial --- docs/source/user_guides.rst | 6 +- docs/source/user_guides/basic_conceptions.rst | 454 ------------------ docs/source/user_guides/basic_concepts.rst | 328 +++++++++++++ 3 files changed, 331 insertions(+), 457 deletions(-) delete mode 100644 docs/source/user_guides/basic_conceptions.rst create mode 100644 docs/source/user_guides/basic_concepts.rst diff --git a/docs/source/user_guides.rst b/docs/source/user_guides.rst index cdb90a035..e2cc76e0a 100644 --- a/docs/source/user_guides.rst +++ b/docs/source/user_guides.rst @@ -1,10 +1,10 @@ User guides ----------- -:doc:`Basic conceptions <./user_guides/basic_conceptions>` +:doc:`Basic concepts <./user_guides/basic_concepts>` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the ``basic conceptions`` tutorial the basics of DFF are described, +In the ``basic concepts`` tutorial the basics of DFF are described, those include but are not limited to: dialog graph creation, specifying start and fallback nodes, setting transitions and conditions, using ``Context`` object in order to receive information about current script execution. @@ -13,4 +13,4 @@ about current script execution. .. toctree:: :hidden: - user_guides/basic_conceptions + user_guides/basic_concepts diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst deleted file mode 100644 index d4ad77225..000000000 --- a/docs/source/user_guides/basic_conceptions.rst +++ /dev/null @@ -1,454 +0,0 @@ -Basic Concepts --------------- - -Introduction -~~~~~~~~~~~~ - -Dialog Flow Framework helps its users create conversational services, which is done by -defining a specialized dialog graph that dictates the behaviour of the dialog service. -This dialog graph essentially represents the dialog script that guides the conversation -between the chat-bot and the user. - -DFF leverages a specialized language known as a Domain-Specific Language (DSL) -to enable developers to quickly write and comprehend dialog graphs. -This DSL greatly simplifies the process of designing complex conversations and handling -various user inputs, making it easier to build sophisticated conversational systems. - -DFF installation and requirements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -For this very basic tutorial we will need only the core dependencies of DFF. -They can be installed via the following command: - -.. code-block:: shell - - pip3 install dff - -Example conversational chat-bot -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Let us go through the creation of a simple bot that would play a (virtual) ping-pong game with its users. -It would also greet them and handle exceptions. -First, we define the chat-bot in pseudo language: - -.. code-block:: text - - If user writes "Hello!": - Respond with "Hi! Let's play ping-pong!" - - If user afterwards writes "Ping" or "ping" or "Ping!" or "ping!": - Respond with "Pong!" - Repeat this behaviour - - If user writes something else: - Respond with "You should've written 'Ping', not '[USER MESSAGE]'!" - Go to responding with "Hi! Let's play ping-pong!" if user writes anything - - If user writes something else: - Respond with "You should've started the dialog with 'Hello!'" - Go to responding with "Hi! Let's play ping-pong!" if user writes anything - -Later in this tutorial we will create this chat-bot using DFF, starting from the very basics -and then elaborating on more complicated topics. - -Example chat-bot graph -~~~~~~~~~~~~~~~~~~~~~~ - -Let's start from creating the very simple dialog agent: - -.. code-block:: python - - from dff.pipeline import Pipeline - from dff.script import TRANSITIONS, RESPONSE, Message - import dff.script.conditions as cnd - - ping_pong_script = { - "ping_pong_flow": { - "start_node": { - RESPONSE: Message(), - TRANSITIONS: { - "greeting_node": cnd.exact_match(Message(text="Hello!")), - }, - }, - "greeting_node": { - RESPONSE: Message(text="Hi! Let's play ping-pong!"), - TRANSITIONS: { - "response_node": cnd.exact_match(Message(text="Ping!")), - }, - }, - "response_node": { - RESPONSE: Message(text="Pong!"), - TRANSITIONS: { - "response_node": cnd.exact_match(Message(text="Ping!")), - }, - }, - "fallback_node": { - RESPONSE: Message(text="That was against the rules!"), - TRANSITIONS: { - "greeting_node": cnd.true(), - }, - }, - }, - } - - pipeline = Pipeline.from_script( - ping_pong_script, - start_label=("ping_pong_flow", "start_node"), - fallback_label=("ping_pong_flow", "fallback_node"), - ) - - if __name__ == "__main__": - pipeline.run() - -.. warning:: - - Current dialog agent doesn't support different cases and/or marks in "Ping" - messages, it only supports exact "Ping!" message from user. - It also supports only one standard error message for any error. - -That's what the agent consists of: - -* ``ping_pong_script``: in order to create a dialog agent, a dialog **script** is needed; - a script is a dictionary, where the keys are the names of the flows (that are "sub-dialogs", - used to separate the whole dialog into multiple sub-dialogs). - -* ``ping_pong_flow`` is our behaviour flow; a flow is a separated dialog, containing linked - conversation nodes and possibly some extra data, transitions, etc. - -* ``start_node`` is the initial node, contains no response, only transfers user to an other node - according to the first message user sends. - It transfers user to ``greeting_node`` if user writes text message exactly equal to "Hello!". - -* Each node contains "RESPONSE" and "TRANSITIONS" elements. - -* ``RESPONSE`` value should be a ``Message`` object, that can contain text, images, - audios, attachments, etc. - -* ``TRANSITIONS`` value should be a dict, containing node names and conditions, - that should be met in order to go to the node specified. - Here, we can see two different types of transitions: ``exact_match`` requires user message text to - match the provided text exactly, while ``true`` allowes unconditional transition. - -* ``greeting_node`` is the node that will greet user and propose him a ping-pong game. - It transfers user to ``response_node`` if user writes text message exactly equal to "Ping!". - -* ``response_node`` is the node that will play ping-pong game with the user. - It transfers user to ``response_node`` if user writes text message exactly equal to "Ping!". - -* ``fallback_node`` is an "exception handling node"; user will be transferred here if in any node - no transition for the message given by user is found. - It transfers user to ``greeting_node`` no matter what user writes. - -* ``pipeline`` is a special object that processes user requests according to provided script. - In order to create a pipeline, the script should be provided and two two-string tuples: - the first specifies initial node flow and name and the second (optional) specifies fallback - node flow and name (if not provided it equals to the first one by default). - -.. note:: - - See `tutorial on basic dialog structure`_. - -Advanced graph features -~~~~~~~~~~~~~~~~~~~~~~~ - -Right now the agent we have created is a very simple one and does not behave **exactly** as we wanted -our bot to behave. Let's see how we can improve our script: - -.. code-block:: python - - from dff.pipeline import Pipeline - from dff.script import TRANSITIONS, RESPONSE, Context, Message - import dff.script.conditions as cnd - import dff.script.labels as lbl - - def get_previous_node_name(ctx: Context) -> str: - """ - Get the name of the previous visited script node. - """ - last_label = sorted(list(ctx.labels))[-2] if len(ctx.labels) >= 2 else None - # labels store the list of nodes the bot transitioned to, - # so the second to last label would be the label of a previous node - return ctx.labels[last_label][1] if last_label is not None else "start_node" - # label is a two-item tuple used to identify a node, - # the first element is flow name and the second is node name - - def fallback_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: - """ - Generate response for fallback node, according to the previous node - we have been to. - If the previous node was `start_node`, a sample message will be returned, - otherwise the message will include user input. - """ - if get_previous_node_name(ctx) == "start_node": - return Message(text="You should've started the dialog with 'Hello!'") - elif ctx.last_request is not None: - last_request = ctx.last_request.text - note = f"You should've written 'Ping', not '{last_request}'!" - return Message(text=f"That was against the rules! {note}") - else: - raise RuntimeError("Error occurred: last request is None!") - - - ping_pong_script = { - "ping_pong_flow": { - "start_node": { - RESPONSE: Message(), - TRANSITIONS: { - lbl.forward(): cnd.exact_match(Message(text="Hello!")), - }, - }, - "greeting_node": { - RESPONSE: Message(text="Hi! Let's play ping-pong!"), - TRANSITIONS: { - lbl.forward(): cnd.regexp(r"^[P|p]ing!?$"), - }, - }, - "ping_pong_node": { - RESPONSE: Message(text="Pong!"), - TRANSITIONS: { - lbl.repeat(): cnd.regexp(r"^[P|p]ing!?$"), - }, - }, - "fallback_node": { - RESPONSE: fallback_response, - TRANSITIONS: { - "greeting_node": cnd.true(), - }, - }, - }, - } - - pipeline = Pipeline.from_script( - ping_pong_script, - start_label=("ping_pong_flow", "start_node"), - fallback_label=("ping_pong_flow", "fallback_node"), - ) - - if __name__ == "__main__": - pipeline.run() - -That's what we've changed: - -* ``fallback_node`` has a callback response, it prints different messages depending on the - previous node. - -.. note:: - - See `tutorial on response functions`_. - -* A special function ``get_previous_node_name`` was written to determine the name of the previous - visited node. It utilizes ``labels`` attribute of the ``Context`` object. - -.. note:: - - See `documentation of Context object`_. - -* Transitions were changed: transitions to next, previous and current node were replaced with special - standard transitions. - -.. note:: - - See `tutorial on transitions`_. - -* Conditions were changed: now regular expressions are used to check user text input value. - -.. note:: - - See `tutorial on conditions`_. - -Further exploration -~~~~~~~~~~~~~~~~~~~ - -There are still a lot of capabilities of Dialog Flow Framework that remain uncovered by this tutorial. - -For example: - -* You can use ``GLOBAL`` transitions that will be available from every node in your script. - See `tutorial on global transitions`_. - -* You can serialize context (available on every transition and response) - to json or dictionary in order to debug it or extract some values. - See `tutorial on context serialization`_. - -* You can alter user input and modify generated responses. - User input can be altered with ``PRE_RESPONSE_PROCESSING`` and will happen **before** response generation. - See `tutorial on pre-response processing`_. - Node response can be modified with ``PRE_TRANSITION_PROCESSING`` and will happen **after** response generation. - See `tutorial on pre-transition processing`_. - -* Additional data ``MISC`` can be added to every node, flow and script itself. - See `tutorial on script MISC`_. - -Conclusion -~~~~~~~~~~ - -In this tutorial, we explored the basics of Dialog Flow Framework (DFF) to build dynamic conversational services. -By using DFF's intuitive Domain-Specific Language (DSL) and well-structured dialog graphs, we created a simple interaction between user and chat-bot. -We covered installation, understanding the DSL and building dialog graph. -However, this is just the beginning. DFF offers a world of possibilities in conversational chat-bot. -With practice and exploration of advanced features, you can create human-like conversations and reach a wider audience by integrating with various platforms. -Now, go forth, unleash your creativity, and create captivating conversational services with DFF. -Happy building! - - -.. _tutorial on basic dialog structure: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.1_basics.html -.. _tutorial on response functions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.3_responses.html -.. _documentation of Context object: https://deeppavlov.github.io/dialog_flow_framework/apiref/dff.script.core.context.html -.. _tutorial on transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.4_transitions.html -.. _tutorial on conditions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.2_conditions.html -.. _tutorial on global transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.5_global_transitions.html -.. _tutorial on context serialization: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.6_context_serialization.html -.. _tutorial on pre-response processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.7_pre_response_processing.html -.. _tutorial on pre-transition processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.9_pre_transitions_processing.html -.. _tutorial on script MISC: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.8_misc.html - - -Basic Concepts --------------- - -============ -Introduction -============ - -The Dialog Flow Framework (DFF) is a modern tool for designing conversational services. - -DFF helps users create conversational services by defining a specialized dialog graph that dictates the behavior of the dialog service. -This dialog graph represents the dialog script that guides the conversation between the chat-bot and the user and covers one or several scenarios. - -This tutorial walks you through the process of creating and maintaining a service with the help of DFF. - - -=========================================== -Creating Conversational Services with DFF -=========================================== - -Installation ------------- - -To get started with DFF, you need to install its core dependencies, which can be done using the following command: - - .. code-block:: shell - - pip3 install dff - - -Defining Dialogue Goals and User Scenarios ------------------------------------------- - -To create a conversational service using Dialog Flow Framework (DFF), you start by defining the overall dialogue goal -and breaking down the dialogue into scenarios based on the user needs that you intend to cover. -DFF leverages a specialized Domain-Specific Language (DSL) that makes it easy to break down the dialog into the parts -that you lay down at this stage. - -Creating Dialogue Flows for User Scenarios -------------------------------------------- - -Once you have DFF installed, you can begin creating dialogue flows for various user scenarios. Let's consider an example of a simple chat-bot that plays a virtual ping-pong game with users and handles exceptions. Here's a snippet of the chat-bot graph: - -.. code-block:: python - - from dff.pipeline import Pipeline - from dff.script import TRANSITIONS, RESPONSE, Message - import dff.script.conditions as cnd - - ping_pong_script = { - "ping_pong_flow": { - "start_node": { - RESPONSE: Message(), - TRANSITIONS: { - "greeting_node": cnd.exact_match(Message(text="Hello!")), - }, - }, - "greeting_node": { - RESPONSE: Message(text="Hi! Let's play ping-pong!"), - TRANSITIONS: { - "response_node": cnd.exact_match(Message(text="Ping!")), - }, - }, - "response_node": { - RESPONSE: Message(text="Pong!"), - TRANSITIONS: { - "response_node": cnd.exact_match(Message(text="Ping!")), - }, - }, - "fallback_node": { - RESPONSE: Message(text="That was against the rules!"), - TRANSITIONS: { - "greeting_node": cnd.true(), - }, - }, - }, - } - - pipeline = Pipeline.from_script( - ping_pong_script, - start_label=("ping_pong_flow", "start_node"), - fallback_label=("ping_pong_flow", "fallback_node"), - ) - -In this code, we define a script with a single dialogue flow that emulates a ping-pong game. -Likewise, if additional scenarios need to be covered, additional flow objects can be embedded into the same script object. - -The flow consists of several nodes, including a start node, a greeting node, a response node, and a fallback node. -Each node has a defined response and transitions based on user input. - -Request Handler Definition --------------------------- - -The request handler definition in DFF involves deciding how user requests will be processed to extract additional parameters. This may include writing code to execute SQL queries or accessing an external API. For example, if the user wants to know the schedule, parameters could be the date and location. After retrieving data from the database or API, you need to process it and ensure it meets expectations. If the data is incorrect or missing, provide error handling logic. - -Generating a Response to the User ----------------------------------- - -Creating a response to the user in DFF involves creating a text or multimedia response from the bot that will be delivered to the user. This response may include data from a database or API, as shown in the previous code example. - -Handling Fallbacks and Errors -------------------------------- - -In DFF, you should provide handling for situations where the user makes requests that the bot cannot answer. Create friendly error messages and, if possible, suggest alternative options. This ensures a smoother user experience even when the bot encounters unexpected inputs. - -Testing and Debugging ----------------------- - -Periodically testing the intent is crucial to ensure it works correctly. You should also be prepared to debug the code and dialogue logic if problems are discovered during testing. This step is essential to iron out any issues and make the bot more reliable. - -Monitoring and Analytics -------------------------- - -Setting up bot performance monitoring and usage analytics is essential to monitor its operation and identify potential issues. Monitoring helps you understand how users are interacting with the bot and whether any improvements are needed. - -Iterative Improvement ----------------------- - -To continually enhance your chat-bot's performance, monitor user feedback and analyze data on bot usage. Gradually improve the dialogue logic and functionality based on the data received. This iterative approach ensures that the bot becomes more effective over time. - -Data Protection ----------------- - -Data protection is a critical consideration in bot development, especially when handling sensitive information. -The DFF framework helps ensure the safety of your application by storing the history and other user data present -in the `Context` object under unique ids and abstracting the storage logic away from the user interface. -As a result, it offers the basic level of data protection making it impossible to gain unlawful access to personal information. - -Documentation --------------- - -Creating documentation is essential for teamwork and future bot maintenance. -Document how the intent works, its parameters, and expected outcomes. -This documentation serves as a reference for developers and stakeholders involved in the project. - -Scaling -------- - -If your bot becomes popular and requires scaling, consider scalability during development. -Scalability ensures that the bot can handle a growing user base without performance issues. -While having only one application instance will suffice in most cases, there are many ways -how you can adapt the application to a high load environment. - -* With the database connection support that DFF offers out of the box, DFF projects -can be easily scaled through sharing the same database between multiple application instances. -However, using an external database is required due to the fact that this is the only kind of storage -that can be efficiently shared between processes. -* Likewise, using multiple database instances to ensure the availability of data is also an option. -* The structure of the `Context` object makes it easy to shard the data storing different subsets -of data across multiple database instances. diff --git a/docs/source/user_guides/basic_concepts.rst b/docs/source/user_guides/basic_concepts.rst new file mode 100644 index 000000000..f728498b4 --- /dev/null +++ b/docs/source/user_guides/basic_concepts.rst @@ -0,0 +1,328 @@ +Basic Concepts +-------------- + +Introduction +~~~~~~~~~~~~ + +The Dialog Flow Framework (DFF) is a modern tool for designing conversational services. + +DFF helps users create conversational services by defining a specialized dialog graph that dictates the behavior of the dialog service. +This dialog graph represents the dialog script that guides the conversation between the chat-bot and the user and covers one or several scenarios. + +This tutorial walks you through the process of creating and maintaining a service with the help of DFF. + +========================================= +Creating Conversational Services with DFF +========================================= + +Installation +~~~~~~~~~~~~ + +To get started with DFF, you need to install its core dependencies, which can be done using the following command: + + .. code-block:: shell + + pip3 install dff + +Defining Dialogue Goals and User Scenarios +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To create a conversational service using Dialog Flow Framework (DFF), you start by defining the overall dialogue goal +and breaking down the dialogue into scenarios based on the user intents that you want to cover. +DFF leverages a specialized Domain-Specific Language (DSL) that makes it easy to break down the dialog +(also referred to as `script`) into the parts that you specify at this stage, aka `flows`. + +Creating Dialogue Flows for User Scenarios +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once you have DFF installed, you can begin creating dialogue flows for various user scenarios. +The flow consists of nodes that represent the states of the dialog, making the whole dialog script +identical to a final state automaton. + +.. note:: + + In other words, the script object has 3 levels of nestedness: + **script - flow - node** + +Let's assume that the only scenario of the service is the chat bot playing ping pong with the user. +I.E. the bot is supposed to reply 'pong' to messages that say 'ping' and handle any other messages as exceptions. +The pseudo-code for the said flow is as follows: + +.. code-block:: text + + If user writes "Hello!": + Respond with "Hi! Let's play ping-pong!" + + If user afterwards writes "Ping" or "ping" or "Ping!" or "ping!": + Respond with "Pong!" + Repeat this behaviour + + If user writes something else: + Respond with "That was against the rules" + Go to responding with "Hi! Let's play ping-pong!" if user writes anything + +This leaves us with a single dialog flow in the dialog graph that we lay down below, with the annotations for +each part of the graph available under the code snippet. + +Example flow & script +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + from dff.pipeline import Pipeline + from dff.script import TRANSITIONS, RESPONSE, Message + import dff.script.conditions as cnd + + ping_pong_script = { + "ping_pong_flow": { + "start_node": { + RESPONSE: Message(text=""), # the response of the initial node is skipped + TRANSITIONS: { + "greeting_node": cnd.exact_match(Message(text="Hello!")), + }, + }, + "greeting_node": { + RESPONSE: Message(text="Hi! Let's play ping-pong!"), + TRANSITIONS: { + "response_node": cnd.exact_match(Message(text="Ping!")), + }, + }, + "response_node": { + RESPONSE: Message(text="Pong!"), + TRANSITIONS: { + "response_node": cnd.exact_match(Message(text="Ping!")), + }, + }, + "fallback_node": { + RESPONSE: Message(text="That was against the rules!"), + TRANSITIONS: { + "greeting_node": cnd.true(), + }, + }, + }, + } + + pipeline = Pipeline.from_script( + ping_pong_script, + start_label=("ping_pong_flow", "start_node"), + fallback_label=("ping_pong_flow", "fallback_node"), + ) + +The code snippet above defines a script with a single dialogue flow that emulates a ping-pong game. +Likewise, if additional scenarios need to be covered, additional flow objects can be embedded into the same script object. + +* ``ping_pong_script``: in order to create a dialog agent, a dialog **script** is needed; + a script is a dictionary, where the keys are the names of the flows (that are "sub-dialogs", + used to separate the whole dialog into multiple sub-dialogs). + +* ``ping_pong_flow`` is our behaviour flow; a flow is a separated dialog, containing linked + conversation nodes and possibly some extra data, transitions, etc. + +* ``start_node`` is the initial node, contains no response, only transfers user to an other node + according to the first message user sends. + It transfers user to ``greeting_node`` if user writes text message exactly equal to "Hello!". + +* Each node contains "RESPONSE" and "TRANSITIONS" elements. + +* ``TRANSITIONS`` value should be a dict, containing node names and conditions, + that should be met in order to go to the node specified. + Here, we can see two different types of transitions: ``exact_match`` requires user message text to + match the provided text exactly, while ``true`` allowes unconditional transition. + +* ``greeting_node`` is the node that will greet user and propose him a ping-pong game. + It transfers user to ``response_node`` if user writes text message exactly equal to "Ping!". + +* ``response_node`` is the node that will play ping-pong game with the user. + It transfers user to ``response_node`` if user writes text message exactly equal to "Ping!". + +* ``fallback_node`` is an "exception handling node"; user will be transferred here if in any node + no transition for the message given by user is found. + It transfers user to ``greeting_node`` no matter what user writes. + +* ``pipeline`` is a special object that processes user requests according to provided script. + In order to create a pipeline, the script should be provided and two two-string tuples: + the first specifies initial node flow and name and the second (optional) specifies fallback + node flow and name (if not provided it equals to the first one by default). + +.. note:: + + See `tutorial on basic dialog structure`_. + +Processing Definition +~~~~~~~~~~~~~~~~~~~~~ + +Processing user requests and extracting additional parameters is a crucial part of building a conversational bot. +DFF allows you to define how user requests will be processed to extract additional parameters. +This is done by passing callbacks to special ``PROCESSING`` fields in the Node object. + +* User input can be altered with ``PRE_RESPONSE_PROCESSING`` and will happen **before** response generation. + See `tutorial on pre-response processing`_. +* Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation. + See `tutorial on pre-transition processing`_. + +Depending on your bot's requirements and the goal of the dialog, you may need to interact with external databases or APIs to retrieve data. +For instance, if a user wants to know a schedule, you may need to access a database and extract parameters such as date and location. + +.. code-block:: python + + import requests + ... + def use_api_processing(ctx: Context, _: Pipeline) -> Context: + ctx.misc["api_call_results"] = requests.get("http://schedule.api/day1") + return ctx + ... + node = { + RESPONSE: ... + TRANSITIONS: ... + PRE_TRANSITIONS_PROCESSING: {"use_api": use_api_processing} + } + +If you retrieve data from the database or API, it's important to validate it to ensure it meets expectations. +Since DFF extensively leverages pydantic, you can resort to the validation tools of this feature-rich library. +For instance, given that each processing routine is a callback, you can use tools like pydantic's `validate_call` +to ensure that the returned values match the function signature. +Error handling logic can also be incorporated into the callbacks. + +Generating a bot Response +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generating a bot response involves creating a text or multimedia response that will be delivered to the user. +Response is defined in the ``RESPONSE`` section of each node and should be either a ``Message`` object, +that can contain text, images, audios, attachments, etc., or a callback that returns a ``Message``. +The latter allows you to customize the response based on the specific scenario and user input. + +.. code-block:: python + + def sample_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: + if ctx.misc["user"] == 'vegan': + return Message(text="Here is a list of vegan cafes.") + return Message(text="Here is a list of cafes.") + +Handling Fallbacks +~~~~~~~~~~~~~~~~~~ + +In DFF, you should provide handling for situations where the user makes requests +that do not trigger any of the specified transitions. +To cover that use case, DFF requires you to define a fallback node that the agent will move to +when no adequate transition has been found. + +Like other nodes, the fallback node can either use a callback to produce a response +which gives you a lot of freedom in creating situationally appropriate error messages. +Create friendly error messages and, if possible, suggest alternative options. +This ensures a smoother user experience even when the bot encounters unexpected inputs. + +.. code-block:: python + + def fallback_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: + """ + Generate a special fallback response if the initial user utterance is not 'Hi'. + """ + last_flow, last_node = ctx.last_label + if ctx.last_request.text != "Hi" and last_node == "start_node": + return Message(text="You should've started the dialog with 'Hello!'") + else: + raise RuntimeError("Error occurred: last request is None!") + +Testing and Debugging +~~~~~~~~~~~~~~~~~~~~~ + +Periodically testing the conversational services is crucial to ensure it works correctly. +You should also be prepared to debug the code and dialogue logic if problems are discovered during testing. +Thorough testing helps identify and resolve any potential problems in the conversation flow. + +The basic testing procedure offered by DFF is the end-to-end testing of the pipeline and the script +that ensures that the pipeline yields correct responses at any given moment. +It requires a sequence of user request - bot response pairs that form the happy path of your +conversational service. + +.. code-block:: python + + happy_path = ( + (Message(text="Hi"), Message(text="Hi! Let's play ping-pong!")), + (Message(text="Ping!"), Message(text="Pong!")) + ) + +A special function is then used to ascertain complete identity of the messages taken from +the happy path and the pipeline. + +.. code-block:: python + + from dff.testing.common import check_happy_path + + check_happy_path(pipeline, happy_path) + +Monitoring and Analytics +~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting up bot performance monitoring and usage analytics is essential to monitor its operation and identify potential issues. +Monitoring helps you understand how users are interacting with the bot and whether any improvements are needed. +Analytics data can provide valuable insights for refining the bot's behavior and responses. + +DFF provides a `statistics` module as an out-of-the-box solution for collecting arbitrary statistical metrics +from your service. Setting up the data collection is as easy as instantiating the relevant class in the same +context with the pipeline. +What's more, the data you obtain can be visualized right away using Apache Superset as a charting engine. + +.. note:: + + More information is available in the respective tutorial. + TODO: insert link + +Iterative Improvement +~~~~~~~~~~~~~~~~~~~~~ + +To continually enhance your chat-bot's performance, monitor user feedback and analyze data on bot usage. +For instance, the statistics or the charts may reveal that some flow is visited by users more frequently or +less frequently than planned. This would mean that adjustments to the transition structure +of the graph need to be made. + +Gradually improve the transition logic and response content based on the data received. +This iterative approach ensures that the bot becomes more effective over time. + +Data Protection +~~~~~~~~~~~~~~~ + +Data protection is a critical consideration in bot development, especially when handling sensitive information. + +.. note:: + + The DFF framework helps ensure the safety of your application by storing the history and other user data present + in the `Context` object under unique ids and abstracting the storage logic away from the user interface. + As a result, it offers the basic level of data protection making it impossible to gain unlawful access to personal information. + +Documentation +~~~~~~~~~~~~~ + +Creating documentation is essential for teamwork and future bot maintenance. +Document how the intent works, its parameters, and expected outcomes. +This documentation serves as a reference for developers and stakeholders involved in the project. + +Scaling +~~~~~~~ + +If your bot becomes popular and requires scaling, consider scalability during development. +Scalability ensures that the bot can handle a growing user base without performance issues. +While having only one application instance will suffice in most cases, there are many ways +how you can adapt the application to a high load environment. + +* With the database connection support that DFF offers out of the box, DFF projects + can be easily scaled through sharing the same database between multiple application instances. + However, using an external database is required due to the fact that this is the only kind of storage + that can be efficiently shared between processes. +* Likewise, using multiple database instances to ensure the availability of data is also an option. +* The structure of the `Context` object makes it easy to shard the data storing different subsets + of data across multiple database instances. + +Further reading +~~~~~~~~~~~~~~~ + +.. _tutorial on basic dialog structure: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.1_basics.html +.. _tutorial on response functions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.3_responses.html +.. _documentation of Context object: https://deeppavlov.github.io/dialog_flow_framework/apiref/dff.script.core.context.html +.. _tutorial on transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.4_transitions.html +.. _tutorial on conditions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.2_conditions.html +.. _tutorial on global transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.5_global_transitions.html +.. _tutorial on context serialization: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.6_context_serialization.html +.. _tutorial on pre-response processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.7_pre_response_processing.html +.. _tutorial on pre-transition processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.9_pre_transitions_processing.html +.. _tutorial on script MISC: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.8_misc.html From 2bc69fed0a8d7c7f651e8349ff8b88b231057c35 Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Mon, 4 Sep 2023 17:00:41 +0300 Subject: [PATCH 03/15] fix problems with list formatting --- docs/source/user_guides/basic_concepts.rst | 26 +++++++++------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/docs/source/user_guides/basic_concepts.rst b/docs/source/user_guides/basic_concepts.rst index f728498b4..2eb6ea721 100644 --- a/docs/source/user_guides/basic_concepts.rst +++ b/docs/source/user_guides/basic_concepts.rst @@ -35,8 +35,8 @@ DFF leverages a specialized Domain-Specific Language (DSL) that makes it easy to Creating Dialogue Flows for User Scenarios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Once you have DFF installed, you can begin creating dialogue flows for various user scenarios. -The flow consists of nodes that represent the states of the dialog, making the whole dialog script +Once you have DFF installed, you can begin creating dialogue flows in your script targeting various user scenarios. +A flow consists of nodes that represent the states of the dialog, making the whole dialog script identical to a final state automaton. .. note:: @@ -155,10 +155,8 @@ Processing user requests and extracting additional parameters is a crucial part DFF allows you to define how user requests will be processed to extract additional parameters. This is done by passing callbacks to special ``PROCESSING`` fields in the Node object. -* User input can be altered with ``PRE_RESPONSE_PROCESSING`` and will happen **before** response generation. - See `tutorial on pre-response processing`_. -* Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation. - See `tutorial on pre-transition processing`_. +* User input can be altered with ``PRE_RESPONSE_PROCESSING`` and will happen **before** response generation. See `tutorial on pre-response processing`_. +* Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation. See `tutorial on pre-transition processing`_. Depending on your bot's requirements and the goal of the dialog, you may need to interact with external databases or APIs to retrieve data. For instance, if a user wants to know a schedule, you may need to access a database and extract parameters such as date and location. @@ -305,24 +303,20 @@ Scalability ensures that the bot can handle a growing user base without performa While having only one application instance will suffice in most cases, there are many ways how you can adapt the application to a high load environment. -* With the database connection support that DFF offers out of the box, DFF projects - can be easily scaled through sharing the same database between multiple application instances. - However, using an external database is required due to the fact that this is the only kind of storage - that can be efficiently shared between processes. +* With the database connection support that DFF offers out of the box, DFF projects can be easily scaled through sharing the same database between multiple application instances. However, using an external database is required due to the fact that this is the only kind of storage that can be efficiently shared between processes. * Likewise, using multiple database instances to ensure the availability of data is also an option. -* The structure of the `Context` object makes it easy to shard the data storing different subsets - of data across multiple database instances. +* The structure of the `Context` object makes it easy to shard the data storing different subsets of data across multiple database instances. Further reading ~~~~~~~~~~~~~~~ .. _tutorial on basic dialog structure: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.1_basics.html -.. _tutorial on response functions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.3_responses.html -.. _documentation of Context object: https://deeppavlov.github.io/dialog_flow_framework/apiref/dff.script.core.context.html .. _tutorial on transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.4_transitions.html .. _tutorial on conditions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.2_conditions.html -.. _tutorial on global transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.5_global_transitions.html -.. _tutorial on context serialization: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.6_context_serialization.html +.. _tutorial on response functions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.3_responses.html .. _tutorial on pre-response processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.7_pre_response_processing.html .. _tutorial on pre-transition processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.9_pre_transitions_processing.html +.. _documentation of Context object: https://deeppavlov.github.io/dialog_flow_framework/apiref/dff.script.core.context.html +.. _tutorial on global transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.5_global_transitions.html +.. _tutorial on context serialization: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.6_context_serialization.html .. _tutorial on script MISC: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.8_misc.html From 7147b0d709252295361918b0901c056568d1ff2b Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Tue, 5 Sep 2023 14:19:42 +0300 Subject: [PATCH 04/15] rename file to basic_conceptions; update file text; --- docs/source/user_guides.rst | 4 +-- ...sic_concepts.rst => basic_conceptions.rst} | 32 ++++++++++--------- 2 files changed, 19 insertions(+), 17 deletions(-) rename docs/source/user_guides/{basic_concepts.rst => basic_conceptions.rst} (89%) diff --git a/docs/source/user_guides.rst b/docs/source/user_guides.rst index e2cc76e0a..edabffa55 100644 --- a/docs/source/user_guides.rst +++ b/docs/source/user_guides.rst @@ -1,7 +1,7 @@ User guides ----------- -:doc:`Basic concepts <./user_guides/basic_concepts>` +:doc:`Basic concepts <./user_guides/basic_conceptions>` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In the ``basic concepts`` tutorial the basics of DFF are described, @@ -13,4 +13,4 @@ about current script execution. .. toctree:: :hidden: - user_guides/basic_concepts + user_guides/basic_conceptions diff --git a/docs/source/user_guides/basic_concepts.rst b/docs/source/user_guides/basic_conceptions.rst similarity index 89% rename from docs/source/user_guides/basic_concepts.rst rename to docs/source/user_guides/basic_conceptions.rst index 2eb6ea721..703e88f8c 100644 --- a/docs/source/user_guides/basic_concepts.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -6,10 +6,13 @@ Introduction The Dialog Flow Framework (DFF) is a modern tool for designing conversational services. -DFF helps users create conversational services by defining a specialized dialog graph that dictates the behavior of the dialog service. -This dialog graph represents the dialog script that guides the conversation between the chat-bot and the user and covers one or several scenarios. +DFF introduces a specialized Domain-Specific Language (DSL) based on standard Python functions and data structures +which makes it very easy for developers with any level of expertise to design a script for user - bot interaction. +The script comes in a form of the *dialog graph* structure that includes the majority of the conversation logic, +and covers one or several user scenarios, all in a single Python dict. -This tutorial walks you through the process of creating and maintaining a service with the help of DFF. +In this tutorial, we describe the basics of DFF API, +and walk you through the process of creating and maintaining a conversational service with the help of DFF. ========================================= Creating Conversational Services with DFF @@ -28,23 +31,21 @@ Defining Dialogue Goals and User Scenarios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To create a conversational service using Dialog Flow Framework (DFF), you start by defining the overall dialogue goal -and breaking down the dialogue into scenarios based on the user intents that you want to cover. -DFF leverages a specialized Domain-Specific Language (DSL) that makes it easy to break down the dialog -(also referred to as `script`) into the parts that you specify at this stage, aka `flows`. +and breaking down the dialogue into smaller scenarios based on the user intents or actions that you want to cover. +DFF's Domain-Specific Language makes it easy to break down the dialog script into small parts that you specify at this stage, aka `flows`. Creating Dialogue Flows for User Scenarios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Once you have DFF installed, you can begin creating dialogue flows in your script targeting various user scenarios. -A flow consists of nodes that represent the states of the dialog, making the whole dialog script -identical to a final state automaton. +Once you have DFF installed, you can define dialogue flows targeting various user scenarios +and to combine them in a global script object. A flow consists of one or more nodes that represent the states of the dialog. .. note:: In other words, the script object has 3 levels of nestedness: **script - flow - node** -Let's assume that the only scenario of the service is the chat bot playing ping pong with the user. +Let's assume that the only user scenario of the service is the chat bot playing ping pong with the user. I.E. the bot is supposed to reply 'pong' to messages that say 'ping' and handle any other messages as exceptions. The pseudo-code for the said flow is as follows: @@ -139,7 +140,8 @@ Likewise, if additional scenarios need to be covered, additional flow objects ca no transition for the message given by user is found. It transfers user to ``greeting_node`` no matter what user writes. -* ``pipeline`` is a special object that processes user requests according to provided script. +* ``pipeline`` is a special object that traverses the script graph based on the values of user input. + It is also capable of executing custom actions that you want to run on every turn of the conversation. In order to create a pipeline, the script should be provided and two two-string tuples: the first specifies initial node flow and name and the second (optional) specifies fallback node flow and name (if not provided it equals to the first one by default). @@ -153,7 +155,7 @@ Processing Definition Processing user requests and extracting additional parameters is a crucial part of building a conversational bot. DFF allows you to define how user requests will be processed to extract additional parameters. -This is done by passing callbacks to special ``PROCESSING`` fields in the Node object. +This is done by passing callbacks to a special ``PROCESSING`` fields in a Node dict. * User input can be altered with ``PRE_RESPONSE_PROCESSING`` and will happen **before** response generation. See `tutorial on pre-response processing`_. * Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation. See `tutorial on pre-transition processing`_. @@ -224,12 +226,12 @@ This ensures a smoother user experience even when the bot encounters unexpected Testing and Debugging ~~~~~~~~~~~~~~~~~~~~~ -Periodically testing the conversational services is crucial to ensure it works correctly. +Periodically testing the conversational service is crucial to ensure it works correctly. You should also be prepared to debug the code and dialogue logic if problems are discovered during testing. Thorough testing helps identify and resolve any potential problems in the conversation flow. -The basic testing procedure offered by DFF is the end-to-end testing of the pipeline and the script -that ensures that the pipeline yields correct responses at any given moment. +The basic testing procedure offered by DFF is end-to-end testing of the pipeline and the script +which ensures that the pipeline yields correct responses for any given input. It requires a sequence of user request - bot response pairs that form the happy path of your conversational service. From 1638a4c27a1dadec2c90e61e6c480881f3cc27ba Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Tue, 5 Sep 2023 15:46:39 +0300 Subject: [PATCH 05/15] update guide paragraphs --- docs/source/user_guides/basic_conceptions.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 703e88f8c..6a8d0996d 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -8,8 +8,9 @@ The Dialog Flow Framework (DFF) is a modern tool for designing conversational se DFF introduces a specialized Domain-Specific Language (DSL) based on standard Python functions and data structures which makes it very easy for developers with any level of expertise to design a script for user - bot interaction. -The script comes in a form of the *dialog graph* structure that includes the majority of the conversation logic, -and covers one or several user scenarios, all in a single Python dict. +The script comes in a form of the *dialog graph* structure that works like a finite state automaton with +each node equal to a specific state of the dialog, i.e. to a conversation turn. +The graph includes the majority of the conversation logic, and covers one or several user scenarios, all in a single Python dict. In this tutorial, we describe the basics of DFF API, and walk you through the process of creating and maintaining a conversational service with the help of DFF. @@ -32,7 +33,8 @@ Defining Dialogue Goals and User Scenarios To create a conversational service using Dialog Flow Framework (DFF), you start by defining the overall dialogue goal and breaking down the dialogue into smaller scenarios based on the user intents or actions that you want to cover. -DFF's Domain-Specific Language makes it easy to break down the dialog script into small parts that you specify at this stage, aka `flows`. +DFF's Domain-Specific Language makes it easy to break down the dialog script into `flows`, i.e. named node groups, +unified by a specific purpose. Creating Dialogue Flows for User Scenarios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -202,11 +204,11 @@ Handling Fallbacks ~~~~~~~~~~~~~~~~~~ In DFF, you should provide handling for situations where the user makes requests -that do not trigger any of the specified transitions. +that do not trigger any of the transitions specified in the script graph. To cover that use case, DFF requires you to define a fallback node that the agent will move to when no adequate transition has been found. -Like other nodes, the fallback node can either use a callback to produce a response +Like other nodes, the fallback node can either use a message or a callback to produce a response which gives you a lot of freedom in creating situationally appropriate error messages. Create friendly error messages and, if possible, suggest alternative options. This ensures a smoother user experience even when the bot encounters unexpected inputs. From c73af5c7d748548f8f5e04bb43e999f869cc4c37 Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Wed, 6 Sep 2023 12:50:27 +0300 Subject: [PATCH 06/15] Add user guide update --- docs/source/user_guides/basic_conceptions.rst | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 6a8d0996d..1f638cfac 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -40,7 +40,7 @@ Creating Dialogue Flows for User Scenarios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Once you have DFF installed, you can define dialogue flows targeting various user scenarios -and to combine them in a global script object. A flow consists of one or more nodes that represent the states of the dialog. +and to combine them in a global script object. A flow consists of one or more nodes that represent conversation turns. .. note:: @@ -121,16 +121,22 @@ Likewise, if additional scenarios need to be covered, additional flow objects ca * ``ping_pong_flow`` is our behaviour flow; a flow is a separated dialog, containing linked conversation nodes and possibly some extra data, transitions, etc. -* ``start_node`` is the initial node, contains no response, only transfers user to an other node - according to the first message user sends. - It transfers user to ``greeting_node`` if user writes text message exactly equal to "Hello!". +* A node object is an atomic part of the script. + The required fields of a node object are ``RESPONSE`` and ``TRANSITIONS``. + +* The ``RESPONSE`` field specifies the response that the dialog agent gives to the user in the current turn. -* Each node contains "RESPONSE" and "TRANSITIONS" elements. +* The ``TRANSITIONS`` field specifies the edges of the dialog graph that link the dialog states. + This is a dictionary that maps labels of other nodes to conditions, i.e. to callback functions that + return `True` or `False`. These conditions determine whether respective nodes can be visited + in the next turn. + In the example script, we use standard transitions: ``exact_match`` requires the user request to + fully match the provided text, while ``true`` always allows a transition. However, passing custom + callbacks that implement arbitrary logic is also an option. -* ``TRANSITIONS`` value should be a dict, containing node names and conditions, - that should be met in order to go to the node specified. - Here, we can see two different types of transitions: ``exact_match`` requires user message text to - match the provided text exactly, while ``true`` allowes unconditional transition. +* ``start_node`` is the initial node, which contains an empty response and only transfers user to an other node + according to the first message user sends. + It transfers user to ``greeting_node`` if user writes text message exactly equal to "Hello!". * ``greeting_node`` is the node that will greet user and propose him a ping-pong game. It transfers user to ``response_node`` if user writes text message exactly equal to "Ping!". @@ -144,9 +150,9 @@ Likewise, if additional scenarios need to be covered, additional flow objects ca * ``pipeline`` is a special object that traverses the script graph based on the values of user input. It is also capable of executing custom actions that you want to run on every turn of the conversation. - In order to create a pipeline, the script should be provided and two two-string tuples: - the first specifies initial node flow and name and the second (optional) specifies fallback - node flow and name (if not provided it equals to the first one by default). + The pipeline can be initialized with a script, and with labels of two nodes: + the entrypoint of the graph, aka the 'start node', and the fallback node + (if not provided it equals the former per default). .. note:: From a05aea175d4ad2a9964c83db4cf5843cf9f3d93f Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Mon, 18 Sep 2023 19:10:30 +0300 Subject: [PATCH 07/15] update basic_conceptions --- docs/source/user_guides/basic_conceptions.rst | 121 ++++++++++++------ 1 file changed, 79 insertions(+), 42 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 1f638cfac..36d93fa92 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -8,8 +8,8 @@ The Dialog Flow Framework (DFF) is a modern tool for designing conversational se DFF introduces a specialized Domain-Specific Language (DSL) based on standard Python functions and data structures which makes it very easy for developers with any level of expertise to design a script for user - bot interaction. -The script comes in a form of the *dialog graph* structure that works like a finite state automaton with -each node equal to a specific state of the dialog, i.e. to a conversation turn. +The script comes in a form of a *dialog graph* where +each node equals a specific state of the dialog, i.e. a specific conversation turn. The graph includes the majority of the conversation logic, and covers one or several user scenarios, all in a single Python dict. In this tutorial, we describe the basics of DFF API, @@ -24,9 +24,9 @@ Installation To get started with DFF, you need to install its core dependencies, which can be done using the following command: - .. code-block:: shell +.. code-block:: shell - pip3 install dff + pip3 install dff Defining Dialogue Goals and User Scenarios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -36,6 +36,10 @@ and breaking down the dialogue into smaller scenarios based on the user intents DFF's Domain-Specific Language makes it easy to break down the dialog script into `flows`, i.e. named node groups, unified by a specific purpose. +For instance, if one of the dialog options that we provide to the user is to play a game, +the bot can have a 'game' node group that targets this subject, while other flows +cover other topics, like telling the time, telling the weather, etc. + Creating Dialogue Flows for User Scenarios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -71,35 +75,38 @@ Example flow & script ~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python + :linenos: from dff.pipeline import Pipeline from dff.script import TRANSITIONS, RESPONSE, Message import dff.script.conditions as cnd ping_pong_script = { - "ping_pong_flow": { + "greeting_flow": { "start_node": { - RESPONSE: Message(text=""), # the response of the initial node is skipped + RESPONSE: Message(), # the response of the initial node is skipped + TRANSITIONS: { + ("ping_pong_flow", "greeting_node"): cnd.exact_match(Message(text="Hello!")), + }, + }, + "fallback_node": { + RESPONSE: Message(text="That was against the rules!"), TRANSITIONS: { - "greeting_node": cnd.exact_match(Message(text="Hello!")), + ("ping_pong_flow", "greeting_node"): cnd.true(), }, }, + }, + "ping_pong_flow": { "greeting_node": { RESPONSE: Message(text="Hi! Let's play ping-pong!"), TRANSITIONS: { - "response_node": cnd.exact_match(Message(text="Ping!")), + ("ping_pong_flow", "response_node"): cnd.exact_match(Message(text="Ping!")), }, }, "response_node": { RESPONSE: Message(text="Pong!"), TRANSITIONS: { - "response_node": cnd.exact_match(Message(text="Ping!")), - }, - }, - "fallback_node": { - RESPONSE: Message(text="That was against the rules!"), - TRANSITIONS: { - "greeting_node": cnd.true(), + ("ping_pong_flow", "response_node"): cnd.exact_match(Message(text="Ping!")), }, }, }, @@ -111,6 +118,9 @@ Example flow & script fallback_label=("ping_pong_flow", "fallback_node"), ) + if __name__ == "__main__": + pipeline.run() + The code snippet above defines a script with a single dialogue flow that emulates a ping-pong game. Likewise, if additional scenarios need to be covered, additional flow objects can be embedded into the same script object. @@ -127,14 +137,14 @@ Likewise, if additional scenarios need to be covered, additional flow objects ca * The ``RESPONSE`` field specifies the response that the dialog agent gives to the user in the current turn. * The ``TRANSITIONS`` field specifies the edges of the dialog graph that link the dialog states. - This is a dictionary that maps labels of other nodes to conditions, i.e. to callback functions that + This is a dictionary that maps labels of other nodes to conditions, i.e. callback functions that return `True` or `False`. These conditions determine whether respective nodes can be visited in the next turn. In the example script, we use standard transitions: ``exact_match`` requires the user request to fully match the provided text, while ``true`` always allows a transition. However, passing custom callbacks that implement arbitrary logic is also an option. -* ``start_node`` is the initial node, which contains an empty response and only transfers user to an other node +* ``start_node`` is the initial node, which contains an empty response and only transfers user to another node according to the first message user sends. It transfers user to ``greeting_node`` if user writes text message exactly equal to "Hello!". @@ -144,29 +154,36 @@ Likewise, if additional scenarios need to be covered, additional flow objects ca * ``response_node`` is the node that will play ping-pong game with the user. It transfers user to ``response_node`` if user writes text message exactly equal to "Ping!". -* ``fallback_node`` is an "exception handling node"; user will be transferred here if in any node - no transition for the message given by user is found. +* ``fallback_node`` is an "exception handling node"; user will be transferred here if + none of the transition conditions (see ``TRANSITIONS``) is satisfied. It transfers user to ``greeting_node`` no matter what user writes. * ``pipeline`` is a special object that traverses the script graph based on the values of user input. It is also capable of executing custom actions that you want to run on every turn of the conversation. The pipeline can be initialized with a script, and with labels of two nodes: - the entrypoint of the graph, aka the 'start node', and the fallback node - (if not provided it equals the former per default). + the entrypoint of the graph, aka the 'start node', and the 'fallback node' + (if not provided it defaults to the same node as 'start node'). .. note:: - See `tutorial on basic dialog structure`_. + See `tutorial on basic dialog structure <../tutorials/tutorials.script.core.1_basics.html>`_. Processing Definition ~~~~~~~~~~~~~~~~~~~~~ +.. note:: + + The topic of this section is explained in greater detail in the following tutorials: + * `Pre-response processing <../tutorials/tutorials.script.core.7_pre_response_processing.html>`_ + * `Pre-transitions processing <../tutorials/tutorials.script.core.9_pre_transitions_processing.html>`_ + * `Pipeline processors <../tutorials/tutorials.pipeline.2_pre_and_post_processors.html>`_ + Processing user requests and extracting additional parameters is a crucial part of building a conversational bot. DFF allows you to define how user requests will be processed to extract additional parameters. This is done by passing callbacks to a special ``PROCESSING`` fields in a Node dict. * User input can be altered with ``PRE_RESPONSE_PROCESSING`` and will happen **before** response generation. See `tutorial on pre-response processing`_. -* Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation. See `tutorial on pre-transition processing`_. +* Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation, but **before** transition to the next node. See `tutorial on pre-transition processing`_. Depending on your bot's requirements and the goal of the dialog, you may need to interact with external databases or APIs to retrieve data. For instance, if a user wants to know a schedule, you may need to access a database and extract parameters such as date and location. @@ -176,16 +193,22 @@ For instance, if a user wants to know a schedule, you may need to access a datab import requests ... def use_api_processing(ctx: Context, _: Pipeline) -> Context: - ctx.misc["api_call_results"] = requests.get("http://schedule.api/day1") + # save to the context field for custom info + ctx.misc["api_call_results"] = requests.get("http://schedule.api/day1").json() return ctx ... node = { RESPONSE: ... TRANSITIONS: ... - PRE_TRANSITIONS_PROCESSING: {"use_api": use_api_processing} + PRETRANSITIONS_PROCESSING: {"use_api": use_api_processing} } -If you retrieve data from the database or API, it's important to validate it to ensure it meets expectations. +If you retrieve data from the database or API, it's important to validate it to ensure it meets expectations. + +.. warning:: + + The logic of DFF implies that the `Context` object must be trivially convertible to JSON. This puts certain limits on the kind of objects that you can store inside the `Context`. + Since DFF extensively leverages pydantic, you can resort to the validation tools of this feature-rich library. For instance, given that each processing routine is a callback, you can use tools like pydantic's `validate_call` to ensure that the returned values match the function signature. @@ -228,6 +251,9 @@ This ensures a smoother user experience even when the bot encounters unexpected last_flow, last_node = ctx.last_label if ctx.last_request.text != "Hi" and last_node == "start_node": return Message(text="You should've started the dialog with 'Hello!'") + elif ctx.last_request is not None: + note = f"You should've written 'Ping', not '{ctx.last_request.text}'!" + return Message(text=f"That was against the rules! {note}") else: raise RuntimeError("Error occurred: last request is None!") @@ -251,7 +277,7 @@ conversational service. ) A special function is then used to ascertain complete identity of the messages taken from -the happy path and the pipeline. +the happy path and the pipeline. The function will play out a dialog with the pipeline acting as a user while checking returned messages. .. code-block:: python @@ -273,8 +299,7 @@ What's more, the data you obtain can be visualized right away using Apache Super .. note:: - More information is available in the respective tutorial. - TODO: insert link + More information is available in the respective `tutorial <../tutorials/tutorials.stats.1_extractor_functions.html>`_. Iterative Improvement ~~~~~~~~~~~~~~~~~~~~~ @@ -302,8 +327,20 @@ Documentation ~~~~~~~~~~~~~ Creating documentation is essential for teamwork and future bot maintenance. -Document how the intent works, its parameters, and expected outcomes. -This documentation serves as a reference for developers and stakeholders involved in the project. +Document how different parts of the script work and how the bot convers the expected interaction scenarios. +It is especially important to document the purpose and functionality of callback functions and pipeline services +that you may have in your project, using Python docstrings. + +.. code-block:: python + + def kitchen_preference_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: + """ + This function returns a user-targeted response depending on the value + of the 'kitchen preference' slot. + """ + ... + +This documentation serves as a reference for developers involved in the project. Scaling ~~~~~~~ @@ -315,18 +352,18 @@ how you can adapt the application to a high load environment. * With the database connection support that DFF offers out of the box, DFF projects can be easily scaled through sharing the same database between multiple application instances. However, using an external database is required due to the fact that this is the only kind of storage that can be efficiently shared between processes. * Likewise, using multiple database instances to ensure the availability of data is also an option. -* The structure of the `Context` object makes it easy to shard the data storing different subsets of data across multiple database instances. +* The structure of the `Context` object makes it easy to vertically partition the data storing different subsets of data across multiple database instances. Further reading ~~~~~~~~~~~~~~~ -.. _tutorial on basic dialog structure: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.1_basics.html -.. _tutorial on transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.4_transitions.html -.. _tutorial on conditions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.2_conditions.html -.. _tutorial on response functions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.3_responses.html -.. _tutorial on pre-response processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.7_pre_response_processing.html -.. _tutorial on pre-transition processing: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.9_pre_transitions_processing.html -.. _documentation of Context object: https://deeppavlov.github.io/dialog_flow_framework/apiref/dff.script.core.context.html -.. _tutorial on global transitions: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.5_global_transitions.html -.. _tutorial on context serialization: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.6_context_serialization.html -.. _tutorial on script MISC: https://deeppavlov.github.io/dialog_flow_framework/tutorials/tutorials.script.core.8_misc.html +* `Tutorial on basic dialog structure <../tutorials/tutorials.script.core.1_basics.html>`_ +* `Tutorial on transitions <../tutorials/tutorials.script.core.4Transitions.html>`_ +* `Tutorial on conditions <../tutorials/tutorials.script.core.2_conditions.html>`_ +* `Tutorial on response functions <../tutorials/tutorials.script.core.3_responses.html>`_ +* `Tutorial on pre-response processing <../tutorials/tutorials.script.core.7_pre_response_processing.html>`_ +* `Tutorial on pre-transition processing <../tutorials/tutorials.script.core.9_preTransitions_processing.html>`_ +* `Documentation of Context object <../apiref/dff.script.core.context.html>`_ +* `Tutorial on global transitions <../tutorials/tutorials.script.core.5_globalTransitions.html>`_ +* `Tutorial on context serialization <../tutorials/tutorials.script.core.6_context_serialization.html>`_ +* `Tutorial on script MISC <../tutorials/tutorials.script.core.8_misc.html>`_ \ No newline at end of file From dd3563f5724e84c9e06bd513af1c97a80051c129 Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Mon, 25 Sep 2023 11:54:43 +0300 Subject: [PATCH 08/15] Minor updates to basic concepts guide --- docs/source/user_guides/basic_conceptions.rst | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 36d93fa92..53cf3c562 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -33,18 +33,20 @@ Defining Dialogue Goals and User Scenarios To create a conversational service using Dialog Flow Framework (DFF), you start by defining the overall dialogue goal and breaking down the dialogue into smaller scenarios based on the user intents or actions that you want to cover. -DFF's Domain-Specific Language makes it easy to break down the dialog script into `flows`, i.e. named node groups, +DFF's Domain-Specific Language makes it easy to break down the dialog script into `flows`, i.e. named groups of nodes unified by a specific purpose. For instance, if one of the dialog options that we provide to the user is to play a game, -the bot can have a 'game' node group that targets this subject, while other flows -cover other topics, like telling the time, telling the weather, etc. +the bot can have a 'game' flow that contains dialog states related to this subject, while other flows +cover other topics, e.g. 'time' flow can include questions and answers related to telling the time, +'weather' to telling the weather, etc. Creating Dialogue Flows for User Scenarios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Once you have DFF installed, you can define dialogue flows targeting various user scenarios -and to combine them in a global script object. A flow consists of one or more nodes that represent conversation turns. +Once you have DFF installed, you can define dialog flows targeting various user scenarios +and combine them in a global script object. A flow consists of one or more nodes +that represent conversation turns. .. note:: @@ -52,8 +54,8 @@ and to combine them in a global script object. A flow consists of one or more no **script - flow - node** Let's assume that the only user scenario of the service is the chat bot playing ping pong with the user. -I.E. the bot is supposed to reply 'pong' to messages that say 'ping' and handle any other messages as exceptions. -The pseudo-code for the said flow is as follows: +The practical implementation of this is that the bot is supposed to reply 'pong' to messages that say 'ping' +and handle any other messages as exceptions. The pseudo-code for the said flow would be as follows: .. code-block:: text @@ -121,14 +123,13 @@ Example flow & script if __name__ == "__main__": pipeline.run() -The code snippet above defines a script with a single dialogue flow that emulates a ping-pong game. +The code snippet defines a script with a single dialogue flow that emulates a ping-pong game. Likewise, if additional scenarios need to be covered, additional flow objects can be embedded into the same script object. -* ``ping_pong_script``: in order to create a dialog agent, a dialog **script** is needed; - a script is a dictionary, where the keys are the names of the flows (that are "sub-dialogs", - used to separate the whole dialog into multiple sub-dialogs). +* ``ping_pong_script``: The dialog **script** mentioned above is a dictionary that has one or more + dialog flows as its values. -* ``ping_pong_flow`` is our behaviour flow; a flow is a separated dialog, containing linked +* ``ping_pong_flow`` is the game emulation flow; it contains linked conversation nodes and possibly some extra data, transitions, etc. * A node object is an atomic part of the script. @@ -185,7 +186,7 @@ This is done by passing callbacks to a special ``PROCESSING`` fields in a Node d * User input can be altered with ``PRE_RESPONSE_PROCESSING`` and will happen **before** response generation. See `tutorial on pre-response processing`_. * Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation, but **before** transition to the next node. See `tutorial on pre-transition processing`_. -Depending on your bot's requirements and the goal of the dialog, you may need to interact with external databases or APIs to retrieve data. +Depending on the requirements of your bot and the dialog goal, you may need to interact with external databases or APIs to retrieve data. For instance, if a user wants to know a schedule, you may need to access a database and extract parameters such as date and location. .. code-block:: python @@ -207,12 +208,12 @@ If you retrieve data from the database or API, it's important to validate it to .. warning:: - The logic of DFF implies that the `Context` object must be trivially convertible to JSON. This puts certain limits on the kind of objects that you can store inside the `Context`. + The logic of DFF implies that the `Context` object must be trivially serializable to JSON. This puts certain limits on the kind of objects that you can store inside the `Context`. Since DFF extensively leverages pydantic, you can resort to the validation tools of this feature-rich library. For instance, given that each processing routine is a callback, you can use tools like pydantic's `validate_call` to ensure that the returned values match the function signature. -Error handling logic can also be incorporated into the callbacks. +Error handling logic can also be incorporated into these callbacks. Generating a bot Response ~~~~~~~~~~~~~~~~~~~~~~~~~ From c3be6a50c38d377f290c4c17567811862ab7e65f Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Thu, 28 Sep 2023 16:16:20 +0300 Subject: [PATCH 09/15] update tutor --- docs/source/user_guides/basic_conceptions.rst | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 53cf3c562..8a3916913 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -175,6 +175,7 @@ Processing Definition .. note:: The topic of this section is explained in greater detail in the following tutorials: + * `Pre-response processing <../tutorials/tutorials.script.core.7_pre_response_processing.html>`_ * `Pre-transitions processing <../tutorials/tutorials.script.core.9_pre_transitions_processing.html>`_ * `Pipeline processors <../tutorials/tutorials.pipeline.2_pre_and_post_processors.html>`_ @@ -184,7 +185,7 @@ DFF allows you to define how user requests will be processed to extract addition This is done by passing callbacks to a special ``PROCESSING`` fields in a Node dict. * User input can be altered with ``PRE_RESPONSE_PROCESSING`` and will happen **before** response generation. See `tutorial on pre-response processing`_. -* Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation, but **before** transition to the next node. See `tutorial on pre-transition processing`_. +* Node response can be modified with ``PRE_TRANSITIONS_PROCESSING`` and will happen **after** response generation but **before** transition to the next node. See `tutorial on pre-transition processing`_. Depending on the requirements of your bot and the dialog goal, you may need to interact with external databases or APIs to retrieve data. For instance, if a user wants to know a schedule, you may need to access a database and extract parameters such as date and location. @@ -193,7 +194,7 @@ For instance, if a user wants to know a schedule, you may need to access a datab import requests ... - def use_api_processing(ctx: Context, _: Pipeline) -> Context: + def use_api_processing(ctx: Context, _: Pipeline, *args, **kwargs) -> Context: # save to the context field for custom info ctx.misc["api_call_results"] = requests.get("http://schedule.api/day1").json() return ctx @@ -201,7 +202,7 @@ For instance, if a user wants to know a schedule, you may need to access a datab node = { RESPONSE: ... TRANSITIONS: ... - PRETRANSITIONS_PROCESSING: {"use_api": use_api_processing} + PRE_TRANSITIONS_PROCESSING: {"use_api": use_api_processing} } If you retrieve data from the database or API, it's important to validate it to ensure it meets expectations. @@ -247,10 +248,10 @@ This ensures a smoother user experience even when the bot encounters unexpected def fallback_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: """ - Generate a special fallback response if the initial user utterance is not 'Hi'. + Generate a special fallback response if the initial user utterance is not 'Hello!'. """ last_flow, last_node = ctx.last_label - if ctx.last_request.text != "Hi" and last_node == "start_node": + if ctx.last_request.text != "Hello!" and last_node == "start_node": return Message(text="You should've started the dialog with 'Hello!'") elif ctx.last_request is not None: note = f"You should've written 'Ping', not '{ctx.last_request.text}'!" @@ -273,7 +274,7 @@ conversational service. .. code-block:: python happy_path = ( - (Message(text="Hi"), Message(text="Hi! Let's play ping-pong!")), + (Message(text="Hello!"), Message(text="Hi! Let's play ping-pong!")), (Message(text="Ping!"), Message(text="Pong!")) ) @@ -328,13 +329,13 @@ Documentation ~~~~~~~~~~~~~ Creating documentation is essential for teamwork and future bot maintenance. -Document how different parts of the script work and how the bot convers the expected interaction scenarios. +Document how different parts of the script work and how the bot covers the expected interaction scenarios. It is especially important to document the purpose and functionality of callback functions and pipeline services that you may have in your project, using Python docstrings. .. code-block:: python - def kitchen_preference_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: + def fav_kitchen_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: """ This function returns a user-targeted response depending on the value of the 'kitchen preference' slot. @@ -359,12 +360,12 @@ Further reading ~~~~~~~~~~~~~~~ * `Tutorial on basic dialog structure <../tutorials/tutorials.script.core.1_basics.html>`_ -* `Tutorial on transitions <../tutorials/tutorials.script.core.4Transitions.html>`_ +* `Tutorial on transitions <../tutorials/tutorials.script.core.4_transitions.html>`_ * `Tutorial on conditions <../tutorials/tutorials.script.core.2_conditions.html>`_ * `Tutorial on response functions <../tutorials/tutorials.script.core.3_responses.html>`_ * `Tutorial on pre-response processing <../tutorials/tutorials.script.core.7_pre_response_processing.html>`_ -* `Tutorial on pre-transition processing <../tutorials/tutorials.script.core.9_preTransitions_processing.html>`_ +* `Tutorial on pre-transition processing <../tutorials/tutorials.script.core.9_pre_transitions_processing.html>`_ * `Documentation of Context object <../apiref/dff.script.core.context.html>`_ -* `Tutorial on global transitions <../tutorials/tutorials.script.core.5_globalTransitions.html>`_ +* `Tutorial on global transitions <../tutorials/tutorials.script.core.5_global_transitions.html>`_ * `Tutorial on context serialization <../tutorials/tutorials.script.core.6_context_serialization.html>`_ * `Tutorial on script MISC <../tutorials/tutorials.script.core.8_misc.html>`_ \ No newline at end of file From 84cd4fc616d2f915886bc5ab86069ecf83ae5222 Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Thu, 28 Sep 2023 18:56:15 +0300 Subject: [PATCH 10/15] update basic conceptions: script --- docs/source/user_guides/basic_conceptions.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 8a3916913..e56a23558 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -88,9 +88,15 @@ Example flow & script "start_node": { RESPONSE: Message(), # the response of the initial node is skipped TRANSITIONS: { - ("ping_pong_flow", "greeting_node"): cnd.exact_match(Message(text="Hello!")), + ("greeting_flow", "greeting_node"): cnd.exact_match(Message(text="Hello!")), }, }, + "greeting_node": { + RESPONSE: Message(text="Hi!"), + TRANSITIONS: { + ("ping_pong_flow", "game_start_node"): cnd.true() + } + }, "fallback_node": { RESPONSE: Message(text="That was against the rules!"), TRANSITIONS: { @@ -99,8 +105,8 @@ Example flow & script }, }, "ping_pong_flow": { - "greeting_node": { - RESPONSE: Message(text="Hi! Let's play ping-pong!"), + "game_start_node": { + RESPONSE: Message(text="Let's play ping-pong!"), TRANSITIONS: { ("ping_pong_flow", "response_node"): cnd.exact_match(Message(text="Ping!")), }, @@ -274,7 +280,8 @@ conversational service. .. code-block:: python happy_path = ( - (Message(text="Hello!"), Message(text="Hi! Let's play ping-pong!")), + (Message(text="Hello!"), Message(text="Hi!")), + (Message(text="hi"), Message(text="Let's play ping-pong!")), (Message(text="Ping!"), Message(text="Pong!")) ) From ffddafdf02a1ca2272dc831eeb4db34c96f086cd Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Fri, 29 Sep 2023 11:27:05 +0300 Subject: [PATCH 11/15] update fallback_response --- docs/source/user_guides/basic_conceptions.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index e56a23558..02a232ed4 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -256,12 +256,12 @@ This ensures a smoother user experience even when the bot encounters unexpected """ Generate a special fallback response if the initial user utterance is not 'Hello!'. """ - last_flow, last_node = ctx.last_label - if ctx.last_request.text != "Hello!" and last_node == "start_node": - return Message(text="You should've started the dialog with 'Hello!'") - elif ctx.last_request is not None: - note = f"You should've written 'Ping', not '{ctx.last_request.text}'!" - return Message(text=f"That was against the rules! {note}") + if ctx.last_request is not None: + if ctx.last_request.text != "Hello!" and ctx.last_label is None: # start node + return Message(text="You should've started the dialog with 'Hello!'") + else: + note = f"You should've written 'Ping', not '{ctx.last_request.text}'!" + return Message(text=f"That was against the rules! {note}") else: raise RuntimeError("Error occurred: last request is None!") From d09e5ea35b65368969e1f20db02b1c102649e50a Mon Sep 17 00:00:00 2001 From: ruthenian8 Date: Mon, 16 Oct 2023 13:34:59 +0300 Subject: [PATCH 12/15] Update script && fallback function --- docs/source/user_guides/basic_conceptions.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 02a232ed4..c0467e98a 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -88,13 +88,13 @@ Example flow & script "start_node": { RESPONSE: Message(), # the response of the initial node is skipped TRANSITIONS: { - ("greeting_flow", "greeting_node"): cnd.exact_match(Message(text="Hello!")), + ("greeting_flow", "greeting_node"): cnd.exact_match(Message(text="/start")), }, }, "greeting_node": { RESPONSE: Message(text="Hi!"), TRANSITIONS: { - ("ping_pong_flow", "game_start_node"): cnd.true() + ("ping_pong_flow", "game_start_node"): cnd.exact_match(Message(text="Hello!")) } }, "fallback_node": { @@ -254,11 +254,11 @@ This ensures a smoother user experience even when the bot encounters unexpected def fallback_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: """ - Generate a special fallback response if the initial user utterance is not 'Hello!'. + Generate a special fallback response if the initial user utterance is not '/start'. """ if ctx.last_request is not None: - if ctx.last_request.text != "Hello!" and ctx.last_label is None: # start node - return Message(text="You should've started the dialog with 'Hello!'") + if ctx.last_request.text != "/start" and ctx.last_label is None: # start node + return Message(text="You should've started the dialog with '/start'") else: note = f"You should've written 'Ping', not '{ctx.last_request.text}'!" return Message(text=f"That was against the rules! {note}") @@ -280,8 +280,8 @@ conversational service. .. code-block:: python happy_path = ( - (Message(text="Hello!"), Message(text="Hi!")), - (Message(text="hi"), Message(text="Let's play ping-pong!")), + (Message(text="/start"), Message(text="Hi!")), + (Message(text="Hello!"), Message(text="Let's play ping-pong!")), (Message(text="Ping!"), Message(text="Pong!")) ) From 12982ff529dd17a302ce2039d52b0ee7bf2bb87f Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Tue, 17 Oct 2023 01:59:07 +0300 Subject: [PATCH 13/15] fix section structure --- docs/source/user_guides/basic_conceptions.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index c0467e98a..60883ff2d 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -15,12 +15,12 @@ The graph includes the majority of the conversation logic, and covers one or sev In this tutorial, we describe the basics of DFF API, and walk you through the process of creating and maintaining a conversational service with the help of DFF. -========================================= + Creating Conversational Services with DFF -========================================= +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Installation -~~~~~~~~~~~~ +============ To get started with DFF, you need to install its core dependencies, which can be done using the following command: @@ -29,7 +29,7 @@ To get started with DFF, you need to install its core dependencies, which can be pip3 install dff Defining Dialogue Goals and User Scenarios -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +========================================== To create a conversational service using Dialog Flow Framework (DFF), you start by defining the overall dialogue goal and breaking down the dialogue into smaller scenarios based on the user intents or actions that you want to cover. @@ -42,7 +42,7 @@ cover other topics, e.g. 'time' flow can include questions and answers related t 'weather' to telling the weather, etc. Creating Dialogue Flows for User Scenarios -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +========================================== Once you have DFF installed, you can define dialog flows targeting various user scenarios and combine them in a global script object. A flow consists of one or more nodes @@ -74,7 +74,7 @@ This leaves us with a single dialog flow in the dialog graph that we lay down be each part of the graph available under the code snippet. Example flow & script -~~~~~~~~~~~~~~~~~~~~~ +===================== .. code-block:: python :linenos: @@ -176,7 +176,7 @@ Likewise, if additional scenarios need to be covered, additional flow objects ca See `tutorial on basic dialog structure <../tutorials/tutorials.script.core.1_basics.html>`_. Processing Definition -~~~~~~~~~~~~~~~~~~~~~ +===================== .. note:: @@ -223,7 +223,7 @@ to ensure that the returned values match the function signature. Error handling logic can also be incorporated into these callbacks. Generating a bot Response -~~~~~~~~~~~~~~~~~~~~~~~~~ +========================= Generating a bot response involves creating a text or multimedia response that will be delivered to the user. Response is defined in the ``RESPONSE`` section of each node and should be either a ``Message`` object, @@ -238,7 +238,7 @@ The latter allows you to customize the response based on the specific scenario a return Message(text="Here is a list of cafes.") Handling Fallbacks -~~~~~~~~~~~~~~~~~~ +================== In DFF, you should provide handling for situations where the user makes requests that do not trigger any of the transitions specified in the script graph. From bfdae1e6ff864f430e4cbe81f6c93ad415310c33 Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Tue, 17 Oct 2023 01:59:57 +0300 Subject: [PATCH 14/15] add links to other guides --- docs/source/user_guides/basic_conceptions.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 60883ff2d..8f2d4ea1d 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -211,11 +211,14 @@ For instance, if a user wants to know a schedule, you may need to access a datab PRE_TRANSITIONS_PROCESSING: {"use_api": use_api_processing} } -If you retrieve data from the database or API, it's important to validate it to ensure it meets expectations. +.. note:: -.. warning:: + This function uses ``Context`` to store the result of a request for other functions to use. + Context is a data structure that keeps all the information about a specific conversation. - The logic of DFF implies that the `Context` object must be trivially serializable to JSON. This puts certain limits on the kind of objects that you can store inside the `Context`. + To learn more about ``Context`` see the `relevant guide <../user_guides/context_guide.html>`__. + +If you retrieve data from the database or API, it's important to validate it to ensure it meets expectations. Since DFF extensively leverages pydantic, you can resort to the validation tools of this feature-rich library. For instance, given that each processing routine is a callback, you can use tools like pydantic's `validate_call` @@ -308,7 +311,7 @@ What's more, the data you obtain can be visualized right away using Apache Super .. note:: - More information is available in the respective `tutorial <../tutorials/tutorials.stats.1_extractor_functions.html>`_. + More information is available in the respective `guide <../user_guides/superset_guide.html>`__. Iterative Improvement ~~~~~~~~~~~~~~~~~~~~~ @@ -329,7 +332,7 @@ Data protection is a critical consideration in bot development, especially when .. note:: The DFF framework helps ensure the safety of your application by storing the history and other user data present - in the `Context` object under unique ids and abstracting the storage logic away from the user interface. + in the ``Context`` object under unique ids and abstracting the storage logic away from the user interface. As a result, it offers the basic level of data protection making it impossible to gain unlawful access to personal information. Documentation @@ -372,7 +375,7 @@ Further reading * `Tutorial on response functions <../tutorials/tutorials.script.core.3_responses.html>`_ * `Tutorial on pre-response processing <../tutorials/tutorials.script.core.7_pre_response_processing.html>`_ * `Tutorial on pre-transition processing <../tutorials/tutorials.script.core.9_pre_transitions_processing.html>`_ -* `Documentation of Context object <../apiref/dff.script.core.context.html>`_ +* `Guide on Context <../user_guides/context_guide.html>`_ * `Tutorial on global transitions <../tutorials/tutorials.script.core.5_global_transitions.html>`_ * `Tutorial on context serialization <../tutorials/tutorials.script.core.6_context_serialization.html>`_ * `Tutorial on script MISC <../tutorials/tutorials.script.core.8_misc.html>`_ \ No newline at end of file From e258b32b7211331b85f1ac4eb472eeba3bf276df Mon Sep 17 00:00:00 2001 From: Roman Zlobin Date: Tue, 17 Oct 2023 02:00:13 +0300 Subject: [PATCH 15/15] fix codeblocks --- docs/source/user_guides/basic_conceptions.rst | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/source/user_guides/basic_conceptions.rst b/docs/source/user_guides/basic_conceptions.rst index 8f2d4ea1d..5344143e0 100644 --- a/docs/source/user_guides/basic_conceptions.rst +++ b/docs/source/user_guides/basic_conceptions.rst @@ -88,19 +88,21 @@ Example flow & script "start_node": { RESPONSE: Message(), # the response of the initial node is skipped TRANSITIONS: { - ("greeting_flow", "greeting_node"): cnd.exact_match(Message(text="/start")), + ("greeting_flow", "greeting_node"): + cnd.exact_match(Message(text="/start")), }, }, "greeting_node": { RESPONSE: Message(text="Hi!"), TRANSITIONS: { - ("ping_pong_flow", "game_start_node"): cnd.exact_match(Message(text="Hello!")) + ("ping_pong_flow", "game_start_node"): + cnd.exact_match(Message(text="Hello!")) } }, "fallback_node": { - RESPONSE: Message(text="That was against the rules!"), + RESPONSE: fallback_response, TRANSITIONS: { - ("ping_pong_flow", "greeting_node"): cnd.true(), + ("greeting_flow", "greeting_node"): cnd.true(), }, }, }, @@ -108,13 +110,15 @@ Example flow & script "game_start_node": { RESPONSE: Message(text="Let's play ping-pong!"), TRANSITIONS: { - ("ping_pong_flow", "response_node"): cnd.exact_match(Message(text="Ping!")), + ("ping_pong_flow", "response_node"): + cnd.exact_match(Message(text="Ping!")), }, }, "response_node": { RESPONSE: Message(text="Pong!"), TRANSITIONS: { - ("ping_pong_flow", "response_node"): cnd.exact_match(Message(text="Ping!")), + ("ping_pong_flow", "response_node"): + cnd.exact_match(Message(text="Ping!")), }, }, }, @@ -122,8 +126,8 @@ Example flow & script pipeline = Pipeline.from_script( ping_pong_script, - start_label=("ping_pong_flow", "start_node"), - fallback_label=("ping_pong_flow", "fallback_node"), + start_label=("greeting_flow", "start_node"), + fallback_label=("greeting_flow", "fallback_node"), ) if __name__ == "__main__": @@ -257,14 +261,17 @@ This ensures a smoother user experience even when the bot encounters unexpected def fallback_response(ctx: Context, _: Pipeline, *args, **kwargs) -> Message: """ - Generate a special fallback response if the initial user utterance is not '/start'. + Generate a special fallback response depending on the situation. """ if ctx.last_request is not None: - if ctx.last_request.text != "/start" and ctx.last_label is None: # start node + if ctx.last_request.text != "/start" and ctx.last_label is None: + # an empty last_label indicates start_node return Message(text="You should've started the dialog with '/start'") else: - note = f"You should've written 'Ping', not '{ctx.last_request.text}'!" - return Message(text=f"That was against the rules! {note}") + return Message( + text=f"That was against the rules!\n" + f"You should've written 'Ping', not '{ctx.last_request.text}'!" + ) else: raise RuntimeError("Error occurred: last request is None!") @@ -293,7 +300,7 @@ the happy path and the pipeline. The function will play out a dialog with the pi .. code-block:: python - from dff.testing.common import check_happy_path + from dff.utils.testing.common import check_happy_path check_happy_path(pipeline, happy_path)