Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rgstephens committed Nov 29, 2024
0 parents commit 1733f48
Show file tree
Hide file tree
Showing 25 changed files with 523 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Rasa Pro CI/CD Example

Empty file added actions/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions actions/action_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# This files contains your custom actions which can be used to run
# custom Python code.
#
# See this guide on how to implement these action:
# https://rasa.com/docs/rasa-pro/concepts/custom-actions


# This is a simple example for a custom action which utters "Hello World!"

# from typing import Any, Text, Dict, List
#
# from rasa_sdk import Action, Tracker
# from rasa_sdk.executor import CollectingDispatcher
#
#
# class ActionHelloWorld(Action):
#
# def name(self) -> Text:
# return "action_hello_world"
#
# def run(self, dispatcher: CollectingDispatcher,
# tracker: Tracker,
# domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
#
# dispatcher.utter_message(text="Hello World!")
#
# return []
30 changes: 30 additions & 0 deletions actions/add_contact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from typing import Any, Dict, List, Text

from rasa_sdk import Action, Tracker
from rasa_sdk.events import SlotSet
from rasa_sdk.executor import CollectingDispatcher

from actions.db import add_contact, get_contacts, Contact


class AddContact(Action):
def name(self) -> str:
return "add_contact"

def run(
self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[str, Any]
) -> List[Dict[Text, Any]]:
contacts = get_contacts(tracker.sender_id)
name = tracker.get_slot("add_contact_name")
handle = tracker.get_slot("add_contact_handle")

if name is None or handle is None:
return [SlotSet("return_value", "data_not_present")]

existing_handles = {c.handle for c in contacts}
if handle in existing_handles:
return [SlotSet("return_value", "already_exists")]

new_contact = Contact(name=name, handle=handle)
add_contact(tracker.sender_id, new_contact)
return [SlotSet("return_value", "success")]
57 changes: 57 additions & 0 deletions actions/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import os
import shutil
import tempfile
from typing import Any, List

from pydantic import BaseModel

from rasa.nlu.utils import write_json_to_file
from rasa.shared.utils.io import read_json_file

ORIGIN_DB_PATH = "db"
CONTACTS = "contacts.json"


class Contact(BaseModel):
name: str
handle: str


def get_session_db_path(session_id: str) -> str:
tempdir = tempfile.gettempdir()
project_name = "calm_starter"
return os.path.join(tempdir, project_name, session_id)


def prepare_db_file(session_id: str, db: str) -> str:
session_db_path = get_session_db_path(session_id)
os.makedirs(session_db_path, exist_ok=True)
destination_file = os.path.join(session_db_path, db)
if not os.path.exists(destination_file):
origin_file = os.path.join(ORIGIN_DB_PATH, db)
shutil.copy(origin_file, destination_file)
return destination_file


def read_db(session_id: str, db: str) -> Any:
db_file = prepare_db_file(session_id, db)
return read_json_file(db_file)


def write_db(session_id: str, db: str, data: Any) -> None:
db_file = prepare_db_file(session_id, db)
write_json_to_file(db_file, data)


def get_contacts(session_id: str) -> List[Contact]:
return [Contact(**item) for item in read_db(session_id, CONTACTS)]


def add_contact(session_id: str, contact: Contact) -> None:
contacts = get_contacts(session_id)
contacts.append(contact)
write_db(session_id, CONTACTS, [c.dict() for c in contacts])


def write_contacts(session_id: str, contacts: List[Contact]) -> None:
write_db(session_id, CONTACTS, [c.dict() for c in contacts])
22 changes: 22 additions & 0 deletions actions/list_contacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Any, Dict, List, Text

from rasa_sdk import Action, Tracker
from rasa_sdk.events import SlotSet
from rasa_sdk.executor import CollectingDispatcher

from actions.db import get_contacts


class ListContacts(Action):
def name(self) -> str:
return "list_contacts"

def run(
self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[str, Any]
) -> List[Dict[Text, Any]]:
contacts = get_contacts(tracker.sender_id)
if len(contacts) > 0:
contacts_list = "".join([f"- {c.name} ({c.handle}) \n" for c in contacts])
return [SlotSet("contacts_list", contacts_list)]
else:
return [SlotSet("contacts_list", None)]
35 changes: 35 additions & 0 deletions actions/remove_contact.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import Any, Dict, List, Text

from rasa_sdk import Action, Tracker
from rasa_sdk.events import SlotSet
from rasa_sdk.executor import CollectingDispatcher

from actions.db import get_contacts, write_contacts


class RemoveContact(Action):
def name(self) -> str:
return "remove_contact"

def run(
self, dispatcher: CollectingDispatcher, tracker: Tracker, domain: Dict[str, Any]
) -> List[Dict[Text, Any]]:
contacts = get_contacts(tracker.sender_id)
handle = tracker.get_slot("remove_contact_handle")

if handle is not None:
contact_indices_with_handle = [
i for i, c in enumerate(contacts) if c.handle == handle
]
if len(contact_indices_with_handle) == 0:
return [SlotSet("return_value", "not_found")]
else:
removed_contact = contacts.pop(contact_indices_with_handle[0])
write_contacts(tracker.sender_id, contacts)
return [
SlotSet("return_value", "success"),
SlotSet("remove_contact_name", removed_contact.name),
]

else:
return [SlotSet("return_value", "missing_handle")]
12 changes: 12 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
recipe: default.v1
language: en
pipeline:
- name: SingleStepLLMCommandGenerator
llm:
model_name: gpt-4
request_timeout: 7
max_tokens: 256

policies:
- name: FlowPolicy
- name: IntentlessPolicy
31 changes: 31 additions & 0 deletions data/flows/add_contact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
flows:
add_contact:
description: add a contact to your contact list
name: add a contact
steps:
- collect: "add_contact_handle"
description: "a user handle starting with @"
- collect: "add_contact_name"
description: "a name of a person"
- collect: "add_contact_confirmation"
ask_before_filling: true
next:
- if: "slots.add_contact_confirmation is not true"
then:
- action: utter_add_contact_cancelled
next: END
- else: add_contact
- id: add_contact
action: add_contact
next:
- if: "slots.return_value = 'success'"
then:
- action: utter_contact_added
next: END
- if: "slots.return_value = 'already_exists'"
then:
- action: utter_contact_already_exists
next: END
- else:
- action: utter_add_contact_error
next: END
14 changes: 14 additions & 0 deletions data/flows/list_contacts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
flows:
list_contacts:
name: list your contacts
description: show your contact list
steps:
- action: list_contacts
next:
- if: "slots.contacts_list"
then:
- action: utter_list_contacts
next: END
- else:
- action: utter_no_contacts
next: END
29 changes: 29 additions & 0 deletions data/flows/remove_contact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
flows:
remove_contact:
name: remove a contact
description: remove a contact from your contact list
steps:
- collect: "remove_contact_handle"
description: "a contact handle starting with @"
- collect: "remove_contact_confirmation"
ask_before_filling: true
next:
- if: "slots.remove_contact_confirmation is not true"
then:
- action: utter_remove_contact_cancelled
next: END
- else: remove_contact
- id: "remove_contact"
action: remove_contact
next:
- if: "slots.return_value == 'success'"
then:
- action: utter_remove_contact_success
next: END
- if: "slots.return_value == 'not_found'"
then:
- action: utter_contact_not_in_list
next: END
- else:
- action: utter_remove_contact_error
next: END
10 changes: 10 additions & 0 deletions db/contacts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"name": "Joe",
"handle": "@JoeMyers"
},
{
"name": "Mary",
"handle": "@MaryLu"
}
]
39 changes: 39 additions & 0 deletions domain/add_contact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
version: "3.1"

actions:
- add_contact

slots:
add_contact_confirmation:
type: bool
mappings:
- type: from_llm
add_contact_name:
type: text
mappings:
- type: from_llm
add_contact_handle:
type: text
mappings:
- type: from_llm

responses:
utter_ask_add_contact_confirmation:
- text: Do you want to add {add_contact_name}({add_contact_handle}) to your contacts?
buttons:
- payload: "/SetSlots(add_contact_confirmation=true)"
title: Yes
- payload: "/SetSlots(add_contact_confirmation=false)"
title: No, cancel
utter_ask_add_contact_handle:
- text: What's the handle of the user you want to add?
utter_ask_add_contact_name:
- text: What's the name of the user you want to add?
utter_add_contact_error:
- text: "Something went wrong, please try again."
utter_add_contact_cancelled:
- text: "Okay, I am cancelling this adding of a contact."
utter_contact_already_exists:
- text: "There's already a contact with that handle in your list."
utter_contact_added:
- text: "Contact added successfully."
17 changes: 17 additions & 0 deletions domain/list_contacts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: "3.1"

actions:
- list_contacts

slots:
contacts_list:
type: text
mappings:
- type: custom
action: list_contacts

responses:
utter_no_contacts:
- text: "You have no contacts in your list."
utter_list_contacts:
- text: "You currently have the following contacts:\n{contacts_list}"
38 changes: 38 additions & 0 deletions domain/remove_contact.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
version: "3.1"

actions:
- remove_contact

slots:
remove_contact_name:
type: text
mappings:
- type: custom
action: remove_contact
remove_contact_handle:
type: text
mappings:
- type: from_llm
remove_contact_confirmation:
type: text
mappings:
- type: from_llm

responses:
utter_ask_remove_contact_handle:
- text: What's the handle of the user you want to remove?
utter_contact_not_in_list:
- text: "That contact is not in your list."
utter_remove_contact_error:
- text: "Something went wrong, please try again."
utter_remove_contact_success:
- text: "Removed {remove_contact_handle}({remove_contact_name}) from your contacts."
utter_ask_remove_contact_confirmation:
- buttons:
- payload: "/SetSlots(remove_contact_confirmation=true)"
title: Yes
- payload: "/SetSlots(remove_contact_confirmation=false)"
title: No, cancel the removal
text: "Should I remove {remove_contact_handle} from your contact list?"
utter_remove_contact_cancelled:
- text: "Okay, I am cancelling this removal of a contact."
10 changes: 10 additions & 0 deletions domain/shared.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: "3.1"

slots:
return_value:
type: any
mappings:
- type: custom
action: add_contact
- type: custom
action: remove_contact
Loading

0 comments on commit 1733f48

Please sign in to comment.