-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a local speechbot service #88
base: develop
Are you sure you want to change the base?
Changes from 25 commits
6468855
c2172c3
f82e66f
606f3e4
c2e74d7
c5c222b
0964d7b
ef5bfbf
29cb991
b58608b
802c646
4da9a9d
a015924
1da6989
ee82337
1984885
02aac16
2175b48
38cf49c
07f526b
ae2c9ef
8cebccf
30b2a2e
a1b229d
e4ae7f0
e378af2
6bddee3
11b3213
e63969b
4c8baf2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
[ | ||
{ | ||
"set": "setup", | ||
"steps": [ | ||
{ | ||
"microphone_default": { | ||
"action_goal": "ON", | ||
"resource_type": "sensor", | ||
"wait_for": "" | ||
} | ||
}, | ||
{ | ||
"stt_default": { | ||
"action_goal": "ON", | ||
"resource_type": "detector", | ||
"wait_for": "" | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
"set": "loop", | ||
"steps": [ | ||
{ | ||
"stt_default": { | ||
"resource_type": "detector", | ||
"wait_for": "new" | ||
} | ||
}, | ||
{ | ||
"bot_default": { | ||
"action_goal": "REQUEST", | ||
"resource_type": "service", | ||
"wait_for": "new" | ||
} | ||
}, | ||
{ | ||
"tts_default": { | ||
"action_goal": "REQUEST", | ||
"resource_type": "service", | ||
"wait_for": "new" | ||
} | ||
}, | ||
[ | ||
{ | ||
"speaker_default": { | ||
"action_goal": "DO", | ||
"resource_type": "actuator", | ||
"wait_for": "new" | ||
} | ||
} | ||
] | ||
] | ||
} | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Common Imports | ||
import rospy | ||
import roslib | ||
|
||
from harmoni_common_lib.constants import State | ||
from harmoni_common_lib.service_server import HarmoniServiceServer | ||
from harmoni_common_lib.service_manager import HarmoniServiceManager | ||
|
||
# Specific Imports | ||
import argparse | ||
import os | ||
import rasa | ||
import threading | ||
from harmoni_common_lib.constants import DialogueNameSpace | ||
from harmoni_bot.rasa_client import RasaClient | ||
|
||
|
||
class RasaService(HarmoniServiceManager): | ||
"""This is a class representation of a harmoni_dialogue service | ||
(HarmoniServiceManager). It is essentially an extended combination of the | ||
:class:`harmoni_common_lib.service_server.HarmoniServiceServer` and | ||
:class:`harmoni_common_lib.service_manager.HarmoniServiceManager` classes | ||
|
||
:param name: Name of the current service | ||
:type name: str | ||
:param param: input parameters of the configuration.yaml file | ||
:type param: from yaml | ||
""" | ||
|
||
def __init__(self, name, param): | ||
"""Constructor method: Initialization of variables and lex parameters + setting up""" | ||
super().__init__(name) | ||
""" Initialization of variables and parameters """ | ||
self.host = param["host"] | ||
self.port = param["port"] | ||
|
||
self.rasa_client = RasaClient( | ||
self.host, | ||
self.port | ||
) | ||
|
||
self.state = State.INIT | ||
return | ||
|
||
def request(self, input_text): | ||
"""[summary] | ||
|
||
Args: | ||
input_text (str): User request (or input text) for triggering Rasa Intent | ||
|
||
Returns: | ||
object: It contains information about the response received (bool) and response message (str) | ||
response: bool | ||
message: str | ||
""" | ||
rospy.loginfo("Start the %s request" % self.name) | ||
self.state = State.REQUEST | ||
|
||
try: | ||
rasa_response = self.rasa_client.get_rasa_response(input_text) | ||
rospy.loginfo(f"The Rasa response is {rasa_response}") | ||
self.state = State.SUCCESS | ||
except Exception as e: | ||
rospy.loginfo(f"Exception occurred: {e}") | ||
self.state = State.FAILED | ||
rasa_response = "" | ||
self.response_received = True | ||
self.result_msg = rasa_response | ||
return {"response": self.state, "message": rasa_response} | ||
|
||
|
||
def main(): | ||
"""[summary] | ||
Main function for starting HarmoniRasa service | ||
""" | ||
service_name = DialogueNameSpace.bot.name | ||
instance_id = rospy.get_param("instance_id") # "default" | ||
service_id = f"{service_name}_{instance_id}" | ||
try: | ||
rospy.init_node(service_name, log_level=rospy.INFO) | ||
params = rospy.get_param("rasa" + "/" + instance_id + "_param/") | ||
s = RasaService(service_id, params) | ||
service_server = HarmoniServiceServer(service_id, s) | ||
service_server.start_sending_feedback() | ||
rospy.spin() | ||
except rospy.ROSInterruptException: | ||
pass | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
rasa==2.7.1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the Rasa version differs between the requirements (2.7.1) file and the docker images (2.4.2)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, the dockerfiles have been updated to 2.7.1 now! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#!/bin/bash | ||
|
||
RASA_ASSISTANT=$(rosparam get /rasa/default_param/rasa_assistant) | ||
RASA_DIR=$(rosparam get /harmoni_bot_dir) | ||
|
||
if [ "$RASA_ASSISTANT" == "rasa_example" ] || [ "$RASA_ASSISTANT" == "rasa_greeter" ] | ||
then | ||
cd "$RASA_DIR"/src/"$RASA_ASSISTANT" | ||
rasa train && rasa run | ||
else | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check works for now, but it doesn't work with future bots. Can we dynamically support based on what directories exist in the RASA_DIR? |
||
echo "Not a valid Rasa bot" | ||
fi | ||
RMichaelSwan marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,16 @@ | ||
# ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD | ||
import os | ||
|
||
from distutils.core import setup | ||
from catkin_pkg.python_setup import generate_distutils_setup | ||
|
||
# fetch values from package.xml | ||
setup_args = generate_distutils_setup( | ||
packages=['harmoni_bot'], | ||
package_dir={'': 'src'}, | ||
package_dir={ | ||
'': 'src', | ||
'harmoni_bot': os.path.join('src', 'harmoni_bot') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as I know this line isn't needed. harmoni_common_lib doesn't have it and is imported the same way. |
||
}, | ||
) | ||
|
||
setup(**setup_args) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#!/usr/bin/env python3 | ||
import logging | ||
import requests | ||
|
||
logging.basicConfig(level=logging.INFO) | ||
|
||
|
||
class RasaClient: | ||
|
||
def __init__( | ||
self, | ||
host="localhost", | ||
port=5005 | ||
): | ||
self._host = host | ||
self._port = port | ||
|
||
def get_rasa_response(self, input_text): | ||
headers = { | ||
'Content-Type': 'application/json', | ||
} | ||
data = '{ "sender": "test_user", "message": "' + input_text + '", "metadata": {} }' | ||
response = requests.post(f"http://{self._host}:{self._port}/webhooks/myio/webhook", headers=headers, data=data) | ||
logging.info(f"Bot response: \n{response.text}\n") | ||
try: | ||
text = response.json()[0]["text"] | ||
except IndexError: | ||
logging.error("Warning: Bad index") | ||
text = "I didn't catch that" | ||
return text | ||
|
||
|
||
if __name__ == "__main__": | ||
rasa_client = RasaClient() | ||
r = "Let's start a conversation with the rasa bot. What would you like to say?\n->" | ||
while True: | ||
i = input(r) | ||
r = rasa_client.get_rasa_response(i) + "\n->" |
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/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 [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can probably delete this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how this line is true; HarmoniServiceServer is really just an extension of the HarmoniActionServer and you have not overridden any of its functions