Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions dialogflow_task_executive/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
cmake_minimum_required(VERSION 2.8.3)
project(dialogflow_task_executive)

if($ENV{ROS_DISTRO} STREQUAL "indigo")
message(WARNING "following requirements.txt syntax is not support on 14.04")
message(WARNING "google-api-core[grpc]==1.31.5 # via google-cloud-language")
find_package(catkin)
catkin_package()
return()
endif()
Comment on lines +4 to +10

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@k-okada Because of these lines, PR2 cannot run dialogflow_task_executive...
PR2 is still Indigo...

execute_process(COMMAND bash -c "gcc -dumpmachine" OUTPUT_VARIABLE gcc_dump_machine OUTPUT_STRIP_TRAILING_WHITESPACE)
message("-- gcc dumpmachine returns ${gcc_dump_machine}")
if(NOT gcc_dump_machine MATCHES "x86_64-.*")
message(WARNING "pip -i requirements.txt work only with i686 ???")
message(WARNING "`pip install grpcio` fails with
third_party/boringssl-with-bazel/src/crypto/hrss/asm/poly_rq_mul.S: Assembler messages:
third_party/boringssl-with-bazel/src/crypto/hrss/asm/poly_rq_mul.S:306: Error: bad register name `%rbp'
third_party/boringssl-with-bazel/src/crypto/hrss/asm/poly_rq_mul.S:308: Error: bad register expression
third_party/boringssl-with-bazel/src/crypto/hrss/asm/poly_rq_mul.S:309: Error: bad register name `%rsp'")
find_package(catkin)
catkin_package()
return()
endif()

find_package(catkin REQUIRED COMPONENTS
message_generation
std_msgs
catkin_virtualenv
)

add_message_files(
Expand All @@ -20,10 +42,12 @@ catkin_package(
CATKIN_DEPENDS message_runtime
)

catkin_generate_virtualenv(INPUT_REQUIREMENTS requirements.in)

install(DIRECTORY node_scripts
file(GLOB NODE_SCRIPTS_FILES node_scripts/*.py)
catkin_install_python(
PROGRAMS ${NODE_SCRIPTS_FILES}
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
USE_SOURCE_PERMISSIONS
)

install(DIRECTORY launch
Expand Down
13 changes: 13 additions & 0 deletions dialogflow_task_executive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ script
end script
```

## Sample programs for JSK users

1. Open [Dialogflow](https://dialogflow.cloud.google.com/?authuser=1#/editAgent/eternal-byte-236613/) and setup Intents and Entities.

2. Download google credentials file. You can download from [Google Drive](https://drive.google.com/file/d/1VxniytpH9J12ii9jphtBylydY1_k5nXf/view?usp=sharing) link.


3. Start sample code

```
roslaunch dialogflow_task_executive demo.launch google_cloud_credentials_json:=${HOME}/Downloads/eternal-byte-236613-4bc6962824d1.json
```

## Author

Yuki Furuta <furushchev@jsk.imi.i.u-tokyo.ac.jp>
Expand Down
24 changes: 19 additions & 5 deletions dialogflow_task_executive/launch/dialogflow_task_executive.launch
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
<launch>
<arg name="run_app_manager" default="false" />
<arg name="credential" default="$(env GOOGLE_APPLICATION_CREDENTIALS)"/>
<arg name="project_id" default="$(env DIALOGFLOW_PROJECT_ID)"/>
<arg name="applist" default="" />
<arg name="credential" default="$(optenv GOOGLE_APPLICATION_CREDENTIALS)"/>
<arg name="project_id" default="$(optenv DIALOGFLOW_PROJECT_ID)"/>
<arg name="enable_hotword" default="true" />

<!-- options for dialogflow_client -->
<arg name="use_audio" default="false" />
<arg name="use_tts" default="true" />
<arg name="language" default="ja-JP" />
<arg name="soundplay_action_name" default="robotsound_jp" />
<arg name="volume" default="1.0" />


<node name="speech_to_text_mux" pkg="topic_tools" type="mux"
args="/speech_to_text /speech_to_text_google /speech_to_text_julius" >
Expand All @@ -12,10 +22,14 @@
pkg="dialogflow_task_executive" type="dialogflow_client.py"
output="screen">
<rosparam subst_value="true">
use_audio: false
language: ja-JP
use_tts: true
use_audio: $(arg use_audio)
use_tts: $(arg use_tts)
language: $(arg language)
soundplay_action_name: $(arg soundplay_action_name)
volume: $(arg volume)
project_id: $(arg project_id)
google_cloud_credentials_json: $(arg credential)
enable_hotword: $(arg enable_hotword)
</rosparam>
</node>

Expand Down
43 changes: 37 additions & 6 deletions dialogflow_task_executive/node_scripts/dialogflow_client.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import rospy
import threading
import uuid
import os

from audio_common_msgs.msg import AudioData
from sound_play.msg import SoundRequest
Expand Down Expand Up @@ -71,8 +72,13 @@ def __init__(self):
# sample rate of audio data
self.audio_sample_rate = rospy.get_param("~audio_sample_rate", 16000)

# if GOOLGE_APPLICATION_CREDENTIALS is not set, use google_cloud_credentials_json param
if not "GOOGLE_APPLICATION_CREDENTIALS" in os.environ:
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = rospy.get_param("~google_cloud_credentials_json")

# use TTS feature
self.use_tts = rospy.get_param("~use_tts", True)
self.volume = rospy.get_param('~volume', 1.0)

# timeout for voice input activation by hotword
self.timeout = rospy.get_param("~timeout", 10.0)
Expand All @@ -88,8 +94,10 @@ def __init__(self):
self.last_spoken = rospy.Time(0)

if self.use_tts:
soundplay_action_name = rospy.get_param(
'~soundplay_action_name', 'robotsound_jp')
self.sound_action = actionlib.SimpleActionClient(
"robotsound_jp", SoundRequestAction)
soundplay_action_name, SoundRequestAction)
if not self.sound_action.wait_for_server(rospy.Duration(5.0)):
self.sound_action = None
else:
Expand All @@ -115,6 +123,8 @@ def __init__(self):
self.sub_speech = rospy.Subscriber(
"speech_to_text", SpeechRecognitionCandidates,
self.input_cb)
self.sub_text = rospy.Subscriber(
"text", String, self.input_cb)

self.df_thread = threading.Thread(target=self.df_run)
self.df_thread.daemon = True
Expand All @@ -137,7 +147,12 @@ def input_cb(self, msg):
self.state.set(State.LISTENING)
elif not self.use_audio:
# catch hotword from string
self.hotword_cb(String(data=msg.transcript[0]))
if isinstance(msg, SpeechRecognitionCandidates):
self.hotword_cb(String(data=msg.transcript[0]))
elif isinstance(msg, String):
self.hotword_cb(data)
else:
rospy.logerr("Unsupported data class {}".format(msg))

if self.state == State.LISTENING:
self.queue.put(msg)
Expand All @@ -164,11 +179,16 @@ def print_result(self, result):
def publish_result(self, result):
msg = DialogResponse()
msg.header.stamp = rospy.Time.now()
if result.action is not 'input.unknown':
if result.action != 'input.unknown':
rospy.logwarn("Unknown action")
msg.query = result.query_text.encode("utf-8")
msg.action = result.action
msg.response = result.fulfillment_text.encode("utf-8")

if self.language == 'ja-JP':
msg.query = result.query_text.encode("utf-8")
msg.response = result.fulfillment_text.encode("utf-8")
else:
msg.query = result.query_text
msg.response = result.fulfillment_text
msg.fulfilled = result.all_required_params_present
msg.parameters = MessageToJson(result.parameters)
msg.speech_score = result.speech_recognition_confidence
Expand All @@ -181,9 +201,17 @@ def speak_result(self, result):
msg = SoundRequest(
command=SoundRequest.PLAY_ONCE,
sound=SoundRequest.SAY,
volume=1.0,
volume=self.volume,
arg=result.fulfillment_text.encode('utf-8'),
arg2=self.language)

# for japanese or utf-8 languages
if self.language == 'ja-JP':
msg.arg = result.fulfillment_text.encode('utf-8')
msg.arg2 = self.language
else:
msg.arg = result.fulfillment_text

self.sound_action.send_goal_and_wait(
SoundRequestGoal(sound_request=msg),
rospy.Duration(10.0))
Expand All @@ -207,6 +235,9 @@ def df_run(self):
elif isinstance(msg, SpeechRecognitionCandidates):
result = self.detect_intent_text(
msg.transcript[0], session)
elif isinstance(msg, String):
result = self.detect_intent_text(
msg.data, session)
else:
raise RuntimeError("Invalid data")
self.print_result(result)
Expand Down
Empty file modified dialogflow_task_executive/node_scripts/task_executive.py
100755 → 100644
Empty file.
4 changes: 3 additions & 1 deletion dialogflow_task_executive/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
<url type="bugtracker">https://github.com/jsk-ros-pkg/jsk_3rdparty/issues</url>

<buildtool_depend>catkin</buildtool_depend>
<build_depend>catkin_virtualenv</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>std_msgs</build_depend>
<run_depend>app_manager</run_depend>
<run_depend>message_runtime</run_depend>
<run_depend>python-dialogflow-pip</run_depend>

<export>
<pip_requirements>requirements.txt</pip_requirements>
</export>

</package>
2 changes: 2 additions & 0 deletions dialogflow_task_executive/requirements.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dialogflow==1.1.1

70 changes: 70 additions & 0 deletions dialogflow_task_executive/samples/client.l
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env roseus

(ros::roseus-add-msgs "dialogflow_task_executive")
(ros::roseus "dialogflow_example")

(defun json-to-list (str)
(let (ret sstr)
;; skip first {
(setq str (string-trim (format nil "{}~% ") str))
;; get first elemnet
(while str
(if (position #\, str)
(setq sstr (subseq str 0 (position #\, str))
str (subseq str (1+ (position #\, str))))
(setq sstr str str nil))
(push (cons (string-trim (format nil "\"~% ") (subseq sstr 0 (position #\: sstr)))
(string-trim (format nil "\"~% ") (subseq sstr (+ (position #\: sstr) 2)))) ret)
)
ret))
(defclass dialogflow-client
:super propertied-object
:slots (response-msg string-msg response-sub publish-tm))

(defmethod dialogflow-client
(:init
()
(setq response-sub (ros::subscribe "/dialog_response" dialogflow_task_executive::DialogResponse #'send self :dialog-cb))
(setq response-msg (instance dialogflow_task_executive::DialogResponse :init))
(setq string-msg (instance std_msgs::String :init))
(ros::advertise "/text" std_msgs::string 1)
;; wait for text publisher
(ros::rate 1)
(while (< (ros::get-num-subscribers "/text") 1)
(ros::sleep))
self)
(:dialog-cb
(msg)
(setq response-msg msg))
(:wait-for-response
()
(while (< (send (ros::time- (send response-msg :header :stamp) publish-tm) :to-sec) 0)
(ros::ros-info "wait for response ... ")
(ros::spin-once)
(ros::sleep))
response-msg)
(:publish-dialog
(text)
(let (ret)
(setq publish-tm (ros::time-now))
(send string-msg :data text)
(ros::publish "/text" string-msg)
(setq ret (send self :wait-for-response))
(send ret :parameters (json-to-list (send ret :parameters)))
(ros::ros-info "action : ~A" (send ret :action))
(ros::ros-info "query : ~A" (send ret :query))
(ros::ros-info "response : ~A" (send ret :response))
(ros::ros-info "parameters : ~A" (send ret :parameters))
(ros::ros-info " speech : ~A" (send ret :speech_score))
(ros::ros-info " intent : ~A" (send ret :intent_score))
ret))
)


(ros::roseus "client")
(setq client (instance dialogflow-client :init))
(send client :publish-dialog "一緒に映画見よう")
(send client :publish-dialog "壁紙がきれいだったよ")
(send client :publish-dialog "一緒に飾り付けしよう")
(send client :publish-dialog "風船を右に置いて")
(exit)
12 changes: 12 additions & 0 deletions dialogflow_task_executive/samples/demo.launch
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<launch>
<arg name="google_cloud_credentials_json" default="" />
<arg name="project_id" default="eternal-byte-236613" />
<include file="$(find dialogflow_task_executive)/launch/dialogflow_task_executive.launch" >
<arg name="credential" value="$(arg google_cloud_credentials_json)" />
<arg name="project_id" value="$(arg project_id)" />
<arg name="run_app_manager" value="true" />
<arg name="enable_hotword" default="false" />
</include>
<node pkg="dialogflow_task_executive" type="client.l"
name="client" output="screen" />
</launch>