Skip to content

Commit

Permalink
Merge branch 'main' into 290-general-activity
Browse files Browse the repository at this point in the history
# Conflicts:
#	Rasa_Bot/actions/helper.py
#	Rasa_Bot/data/nlu.yml
#	Rasa_Bot/models/20221014-151911-hot-dodecagon.tar.gz
  • Loading branch information
wbaccinelli committed Nov 10, 2022
2 parents ab33b40 + e9956c8 commit 36b4965
Show file tree
Hide file tree
Showing 16 changed files with 464 additions and 28 deletions.
1 change: 1 addition & 0 deletions Rasa_Bot/actions/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ WORKDIR /app
# Copy actions requirements
COPY requirements-actions.txt ./

COPY tst.PNG ./
# Change to root user to install dependencies
USER root

Expand Down
63 changes: 60 additions & 3 deletions Rasa_Bot/actions/actions_common.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import logging

from celery import Celery
from niceday_client import NicedayClient
from rasa_sdk import Action
from rasa_sdk.events import FollowupAction
from .definitions import REDIS_URL

from rasa_sdk.events import FollowupAction, SlotSet
from .definitions import REDIS_URL, NICEDAY_API_ENDPOINT

celery = Celery(broker=REDIS_URL)

Expand Down Expand Up @@ -37,3 +37,60 @@ async def run(self, dispatcher, tracker, domain):
logging.info("no celery error")

return []


class SendMetadata(Action):
def name(self):
return "action_send_metadata"

async def run(self, dispatcher, tracker, domain):
"""
Sends the text message specified in the 'text' value of the json_message,
and sends the image identified by the id_file under the 'attachmentIds' key.
The id_file is obtained in the action_upload_file as a result of
a file uploaded to the NiceDay server. The id is stored in the
uploaded_file_id slot.
The uploaded file is a local one, and is uses the file indicated
by the action_set_file_path
"""
id_file = tracker.get_slot("uploaded_file_id")
dispatcher.utter_message(
json_message={"text": "image",
"attachmentIds": [id_file]},
)
return[]


class UploadFile(Action):
def name(self):
return "action_upload_file"

async def run(self, dispatcher, tracker, domain):
client = NicedayClient(NICEDAY_API_ENDPOINT)
user_id = int(tracker.current_state()['sender_id'])

filepath = tracker.get_slot('upload_file_path')
with open(filepath, 'rb') as content:
file = content.read()

response = client.upload_file(user_id, filepath, file)
file_id = response['id']
logging.info(response)
logging.info(file_id)

return[SlotSet("uploaded_file_id", file_id)]


class SetFilePath(Action):
def name(self):
return "action_set_file_path"

async def run(self, dispatcher, tracker, domain):

# TODO: This is hardcoded for testing. Needs to be set according to the use case

filepath = '/app/tst.PNG'

return[SlotSet("upload_file_path", filepath)]
38 changes: 37 additions & 1 deletion Rasa_Bot/actions/actions_minimum_functional_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
"""
import datetime
import logging
from typing import Text, Dict, Any

from dateutil.relativedelta import relativedelta
from dateutil.rrule import rrule, DAILY
from niceday_client import NicedayClient, definitions
from paalgorithms import weekly_kilometers
from rasa_sdk import Action
from rasa_sdk import Action, Tracker
from rasa_sdk.events import SlotSet
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.forms import FormValidationAction
from virtual_coach_db.dbschema.models import Users
from virtual_coach_db.helper.helper_functions import get_db_session

Expand Down Expand Up @@ -175,3 +178,36 @@ async def run(self, dispatcher, tracker, domain):
"This is a tracker",
recursive_rule)
return[]


class ValidateActivityGetFileForm(FormValidationAction):
def name(self) -> Text:
return 'validate_activity_get_file_form'

def validate_received_file_text(
self, slot_value: Text, dispatcher: CollectingDispatcher,
tracker: Tracker, domain: Dict[Text, Any]) -> Dict[Text, Any]:
# pylint: disable=unused-argument
"""Validate the presence of an attached file"""

# here the message metadata are retrieved
events = tracker.current_state()['events']

user_events = [e for e in events if e['event'] == 'user']
# we defined the metadata key name 'attachmentIds' is defined in the broker
received_file_ids_list = user_events[-1]['metadata']['attachmentIds']

if not self._is_valid_input(received_file_ids_list):
dispatcher.utter_message(response="utter_no_attachment")
return {"received_file_text": None}

# At this point the file ID should be saved in the DB for
# re-accessing the shared file

return {"received_file_text": slot_value}

@staticmethod
def _is_valid_input(value):
if len(value) == 0:
return False
return True
117 changes: 116 additions & 1 deletion Rasa_Bot/actions/actions_preparation_dialogs.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
"""
Contains custom actions related to the preparation dialogs
"""
from typing import Text, Any, Dict
from datetime import datetime

from rasa_sdk import Action
from rasa_sdk import Tracker, FormValidationAction, Action
from rasa_sdk.events import SlotSet
from rasa_sdk.executor import CollectingDispatcher
from rasa_sdk.types import DomainDict
from virtual_coach_db.helper.definitions import PreparationInterventionComponents

from .helper import (store_user_preferences_to_db, get_intervention_component_id,
week_day_to_numerical_form)

YES_OR_NO = ["yes", "no"]
ALLOWED_WEEK_DAYS = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]

### Slot-setting methods called for rasa to store current intervention component
class SetSlotProfileCreation(Action):
Expand Down Expand Up @@ -60,3 +69,109 @@ def name(self):
async def run(self, dispatcher, tracker, domain):
return [SlotSet("current_intervention_component",
PreparationInterventionComponents.GOAL_SETTING)]

class ValidateUserPreferencesForm(FormValidationAction):
def name(self) -> Text:
return "validate_user_preferences_form"

def validate_recursive_reminder(
self,
slot_value: Any,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: DomainDict,
) -> Dict[Text, Any]:
# pylint: disable=unused-argument
"""Validate recursive_reminder` value."""
if slot_value.lower() not in YES_OR_NO:
dispatcher.utter_message(text="We only accept 'yes' or 'no' as answers")
return {"recursive_reminder": None}
dispatcher.utter_message(text=f"OK! You have answered {slot_value}.")
return {"recursive_reminder": slot_value}

def validate_week_days(
self,
slot_value: Any,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: DomainDict,
) -> Dict[Text, Any]:
# pylint: disable=unused-argument
"""Validate `week_days` value."""

week_days_string = slot_value
week_days_list = week_days_string.split(", ")
invalidinput = False

for weekday in week_days_list:
if weekday.lower() not in ALLOWED_WEEK_DAYS:
invalidinput = True

if invalidinput:
dispatcher.utter_message(text="Please submit the days of the week as" +
" a comma separated list!")
return {"week_days": None}
dispatcher.utter_message(text="OK! You want to receive reminders on these" +
f" days of the week: {slot_value}.")
return {"week_days": slot_value}

def validate_time_stamp(
self,
slot_value: Any,
dispatcher: CollectingDispatcher,
tracker: Tracker,
domain: DomainDict,
) -> Dict[Text, Any]:
# pylint: disable=unused-argument
"""Validate `time_stamp` value."""

timestring = slot_value
timeformat = "%H:%M:%S"
res = False

# using try-except to check for truth value
try:
res = bool(datetime.strptime(timestring, timeformat))
except ValueError:
res = False

if not res:
dispatcher.utter_message(text="Please submit an answer as given by the example:" +
" 20:34:20")
return {"time_stamp": None}
dispatcher.utter_message(text=f"OK! You want to receive reminders at {slot_value}.")
return {"time_stamp": slot_value}

class StoreUserPreferencesToDb(Action):
def name(self) -> Text:
return "action_store_user_preferences_to_db"

async def run(self, dispatcher, tracker, domain):
user_id = tracker.current_state()['sender_id']

recursive = tracker.get_slot("recursive_reminder")
week_days = tracker.get_slot("week_days")
preferred_time_string = tracker.get_slot("time_stamp")

recursive_bool = False
if recursive in ('yes', 'Yes'):
recursive_bool = True

week_days_numbers = ""
week_days_list = week_days.split(", ")
for weekday in week_days_list:
week_days_numbers += str(week_day_to_numerical_form(weekday))
week_days_numbers += ","

##TODO Set the slot in rasa
# When calling this in the right context, the intervention component slot should have
# a value.Uncomment the next two lines and remove the one under those two to switch
# from a hardcoded intervention component to the one decided by the slot.
##intervention_component_string = tracker.get_slot("current_intervention_component")
##intervention_component = get_intervention_component_id(intervention_component_string)
intervention_component = get_intervention_component_id("profile_creation")

datetime_format = datetime.strptime(preferred_time_string, '%H:%M:%S')

store_user_preferences_to_db(user_id, intervention_component, recursive_bool,
week_days_numbers.rstrip(week_days_numbers[-1]), datetime_format)
35 changes: 33 additions & 2 deletions Rasa_Bot/actions/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import datetime

from .definitions import DialogQuestions, DATABASE_URL, TIMEZONE
from virtual_coach_db.dbschema.models import (Users, DialogAnswers, InterventionComponents)
from virtual_coach_db.dbschema.models import (Users, DialogAnswers, InterventionComponents,
UserPreferences)
from virtual_coach_db.helper.helper_functions import get_db_session


Expand All @@ -15,10 +16,22 @@ def store_dialog_answer_to_db(user_id, answer, question: DialogQuestions):
entry = DialogAnswers(answer=answer,
question_id=question.value,
datetime=datetime.datetime.now().astimezone(TIMEZONE))

selected.dialog_answers.append(entry)
session.commit() # Update database

def store_user_preferences_to_db(user_id, intervention_component, recursive, week_days,
preferred_time):
session = get_db_session(db_url=DATABASE_URL) # Create session object to connect db
selected = session.query(Users).filter_by(nicedayuid=user_id).one()

entry = UserPreferences(users_nicedayuid=user_id,
intervention_component_id=intervention_component,
recursive=recursive,
week_days=week_days,
preferred_time=preferred_time)
selected.user_preferences.append(entry)
session.commit() # Update database


def get_intervention_component_id(intervention_component_name: str) -> int:
"""
Expand Down Expand Up @@ -55,3 +68,21 @@ def get_latest_bot_utterance(events) -> str:
last_utterance = None

return last_utterance


def week_day_to_numerical_form(week_day):
if week_day.lower() == "monday":
return 1
if week_day.lower() == "tuesday":
return 2
if week_day.lower() == "wednesday":
return 3
if week_day.lower() == "thursday":
return 4
if week_day.lower() == "friday":
return 5
if week_day.lower() == "saturday":
return 6
if week_day.lower() == "sunday":
return 7
return -1
Binary file added Rasa_Bot/actions/tst.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 36b4965

Please sign in to comment.