Skip to content

Commit

Permalink
Add support for using variables inside bot message definitions.
Browse files Browse the repository at this point in the history
  • Loading branch information
drazvan committed Jul 27, 2023
1 parent 755ee8a commit d96401f
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Changed the naming of the internal events to align to the upcoming UMIM spec (Unified Multimodal Interaction Management).
comments.)
- Add support for [using variables inside bot message definitions](./docs/user_guide/colang-language-syntax-guide.md#bot-messages-with-variables).

### Fixed

Expand Down
18 changes: 18 additions & 0 deletions docs/user_guide/colang-language-syntax-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ define bot ask welfare

If more than one utterance is specified per bot message, the meaning is that one of them should be chosen randomly.

##### Bot Messages with Variables

The utterance definition can also include reference to variables (see the [Variables](#variables) section below).

```colang
define bot express greeting
"Hello there, $name!"
```

Alternatively, you can also use the Jinja syntax:

```colang
define bot express greeting
"Hello there, {{ name }}!"
```

**NOTE**: for more advanced use cases you can also use other Jinja features like `{% if ... %} ... {% endif %}`.

#### Flows

Flows represent how you want the conversation to unfold. It includes sequences of user messages, bot messages and potentially other events.
Expand Down
42 changes: 42 additions & 0 deletions nemoguardrails/actions/llm/generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from functools import lru_cache
from typing import List, Optional

from jinja2 import Environment, meta
from langchain.llms import BaseLLM

from nemoguardrails.actions.actions import ActionResult, action
Expand Down Expand Up @@ -88,6 +89,9 @@ def __init__(

self.llm_task_manager = llm_task_manager

# We also initialize the environment for rendering bot messages
self.env = Environment()

def _init_user_message_index(self):
"""Initializes the index of user messages."""

Expand Down Expand Up @@ -409,6 +413,41 @@ async def generate_next_step(

return ActionResult(return_value=None)

def _render_string(
self,
template_str: str,
context: Optional[dict] = None,
) -> str:
"""Render a string using the provided context information.
Args:
template_str: The string template to render.
context: The context for rendering.
Returns:
The rendered string.
"""
# First, if we have any direct usage of variables in the string,
# we replace with correct Jinja syntax.
for param in re.findall(r"\$([^ \"'!?\-,;</]*(?:\w|]))", template_str):
template_str = template_str.replace(f"${param}", "{{" + param + "}}")

template = self.env.from_string(template_str)

# First, we extract all the variables from the template.
variables = meta.find_undeclared_variables(self.env.parse(template_str))

# This is the context that will be passed to the template when rendering.
render_context = {}

# Copy the context variables to the render context.
if context:
for variable in variables:
if variable in context:
render_context[variable] = context[variable]

return template.render(render_context)

@action(is_system_action=True)
async def generate_bot_message(
self, events: List[dict], context: dict, llm: Optional[BaseLLM] = None
Expand All @@ -435,6 +474,9 @@ async def generate_bot_message(

log.info("Found existing bot message: " + bot_utterance)

# We also need to render
bot_utterance = self._render_string(bot_utterance, context)

# Check if the output is supposed to be the content of a context variable
elif bot_intent[0] == "$" and bot_intent[1:] in context:
bot_utterance = context[bot_intent[1:]]
Expand Down
55 changes: 43 additions & 12 deletions tests/test_bot_message_rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,20 @@
from nemoguardrails import RailsConfig
from tests.utils import TestChat

config = RailsConfig.from_content(
"""
define user express greeting
"hello"

define flow
user ask time
$now = "12pm"
bot $now
"""
)
def test_1():
config = RailsConfig.from_content(
"""
define user express greeting
"hello"
define flow
user ask time
$now = "12pm"
bot $now
"""
)

def test_1():
"""Test that branching with `when` works correctly."""
chat = TestChat(
config,
llm_completions=[
Expand All @@ -40,3 +39,35 @@ def test_1():

chat >> "What is the time?!"
chat << "12pm"


def test_2():
config = RailsConfig.from_content(
"""
define user express greeting
"hello"
define bot express greeting
"Hello, {{ name }}!"
define bot express greeting again
"Hello, $name!"
define flow
user express greeting
$name = "John"
bot express greeting
bot express greeting again
"""
)

chat = TestChat(
config,
llm_completions=[
" express greeting",
],
)

chat >> "Hi!"
chat << "Hello, John!\nHello, John!"

0 comments on commit d96401f

Please sign in to comment.