Skip to content
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 chaplus ros interface #252

Merged
merged 6 commits into from
Jun 10, 2021
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
32 changes: 32 additions & 0 deletions chaplus_ros/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 2.8.3)
project(chaplus_ros)

find_package(catkin REQUIRED COMPONENTS)

## System dependencies are found with CMake's conventions

catkin_python_setup()

catkin_package()

###########
## Build ##
###########

include_directories()

#############
## Install ##
#############

file(GLOB SCRIPTS_FILES scripts/*)

catkin_install_python(
PROGRAMS ${SCRIPTS_FILES}
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

install(
DIRECTORY sample/
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION})

72 changes: 72 additions & 0 deletions chaplus_ros/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
chaplus_ros
===========

ROS package for https://www.chaplus.jp/

## Tutorials

1) Obtain API keys for chaplus service, go to https://www.chaplus.jp/api

You can also create account via https://chaplus.work and reqeust [beta program](https://forms.gle/DQWXdXzUH4MnE5wv6)

2) Put API key as json file under `` `rospack find chaplus_ros`/apikey.json ``
```
{"apikey": "0123456789"}
```

## Interface

### Subscribing Topics

- request (std_msgs/String)

Input text data for chaplus bot system.

### Publishing Topics

- response (std_msgs/String)

Response text data from chaplus bot system.

### Parameters

- ~chaplus_apikey_file (String: default: `rospack find chaplus_ros`/apikey.json

Path to json file stores chaplus API key.

Sample Code
-----------

1) sample/julius_example.launch

Example to listen from your mic and respond from speakers, This demo uses Julius for speech to text engine, which requires vocabulary list. You need to change following line of the `julius_example.launch` to let system recognize your talk. Note that julius needs 20-30 seconds to update it's vocabulary list, so please be patient after you send the list from your command line.
```
<!-- julius needs vocabulary list -->
<node pkg="rosservice" type="rosservice" name="update_vocabulary_list"
args='call --wait /speech_recognition "{vocabulary: {words: ["こんにちは", "おはよう"]}}"' />
```

2) sample/google_example.launch

Example with google speech recognition. This demo requires [google_cloud_credentials_json](https://github.com/jsk-ros-pkg/jsk_3rdparty/tree/master/ros_speech_recognition#parameters), and update following line of the `google_example.launch`
```
<param name="/speech_recognition/google_cloud_credentials_json"
value="/home/k-okada/Downloads/eternal-byte-236613-4bc6962824d1.json" />
```

## Use other chat API
### A3RT
If you want to use [A3RT](https://a3rt.recruit-tech.co.jp/product/talkAPI)
1) Get A3RT APIKey
Please access https://a3rt.recruit-tech.co.jp/product/talkAPI/registered/ and enter your information.

2) Write A3RT API key in json file under `` `rospack find chaplus_ros`/apikey.json ``
```
{"apikey": "0123456789",
"apikey_a3rt": "abcdefgh"}
```

3) raunch with A3RT option
```
roslaunch chaplus_ros google_example.launch chatbot_engine:=A3RT
```
2 changes: 2 additions & 0 deletions chaplus_ros/apikey.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{"apikey": "0123456789",
"apikey_a3rt": "abcdefgh"}
21 changes: 21 additions & 0 deletions chaplus_ros/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<package format="2">
<name>chaplus_ros</name>
<version>2.1.21</version>
<description>The ROS package for chaplus service</description>

<maintainer email="k-okada@jsk.t.u-tokyo.ac.jp">Kei Okada</maintainer>

<license>BSD</license>

<author email="a-fujii@jsk.imi.i.u-tokyo.ac.jp">Ayaka Fujii</author>

<buildtool_depend>catkin</buildtool_depend>

<exec_depend>rospy</exec_depend>
<exec_depend>python-requests</exec_depend>
<exec_depend>rospy</exec_depend>

<export>
</export>
</package>
50 changes: 50 additions & 0 deletions chaplus_ros/sample/google_example.launch
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<launch>

<!-- you can choose chatbot_engine "Chaplus" or "A3RT" currently-->
<arg name="chatbot_engine" default="Chaplus" />

<!-- start talker
subscribe /robotsound_jp sound_play/SoundRequest -->
<include file="$(find aques_talk)/launch/aques_talk.launch" />

<!-- start listener
publishes /Tablet/voice speech_recognition_msgs/SpeechRecognitionCandidates -->
<include file="$(find ros_speech_recognition)/launch/speech_recognition.launch" >
<arg name="launch_sound_play" value="false" />
<arg name="continuous" value="true" />
<arg name="engine" default="GoogleCloud" />
<arg name="language" value="ja" />
<arg name="n_channel" value="2" />
<arg name="depth" value="16" />
<arg name="sample_rate" value="44100" />
<arg name="device" value="hw:0,0" />
</include>
<param name="/speech_recognition/google_cloud_credentials_json"
value="/home/a-fujii/Downloads/eternal-byte-236613-4bc6962824d1.json" />
<!--
<param name="/speech_recognition/diarizationConfig"
type="yaml"
value="{'enableSpeakerDiarization': True, 'maxSpeakerCount': 3}" />
-->

<!-- node to convert /Tablet/voice (speech_recognition_msgs/SpeechRecognitionCandidates) to /request (std_msgs/String)
c.f.: https://github.com/ros/ros_comm/pull/639#issuecomment-618750038 -->
<node pkg="topic_tools" type="relay_field" name="sound_request_to_request"
args="--wait-for-start /Tablet/voice /request std_msgs/String
'data: m.transcript[0]'" />

<!-- node to convert /response (std_msgs/String) to /robotsound_jp (sound_play/SoundRequest) -->
<node pkg="topic_tools" type="relay_field" name="string_to_sound_request"
args="--wait-for-start /response /robotsound_jp sound_play/SoundRequest
'{sound: -3, command: 1, volume: 1.0, arg: m.data}'" />

<!-- start chaplus
subscribe /request and publish /response -->
<node pkg="chaplus_ros" type="chaplus_ros.py" name="chaplus_ros"
output="screen" >
<rosparam subst_value="true">
chatbot_engine: $(arg chatbot_engine)
</rosparam>
</node>

</launch>
143 changes: 143 additions & 0 deletions chaplus_ros/scripts/chaplus_ros.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Software License Agreement (BSD License)
#
# Copyright (c) 2020, JSK Robotics Lab.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of JSK Robotics, Lab. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

# Author: Ayaka Fujii <a-fujii@jsk.imi.i.u-tokyo.ac.jp>

import rospy
import rospkg
from std_msgs.msg import String
import requests
import json
import sys
import re

if sys.version_info.major == 2:
reload(sys)
sys.setdefaultencoding('utf-8')


class ChaplusROS(object):

def __init__(self):

self.chatbot_engine = rospy.get_param("~chatbot_engine", "Chaplus")
# please write your apikey to chaplus_ros/apikey.json
r = rospkg.RosPack()
apikey_path = rospy.get_param(
"~chaplus_apikey_file", r.get_path('chaplus_ros')+"/apikey.json")
try:
with open(apikey_path) as j:
apikey_json = json.loads(j.read())
except Exception as e:
rospy.logerr('Could not find {}'.format(apikey_path))
rospy.logerr('please add your API keys to chaplus, for example')
rospy.logerr(
"echo '{\"apikey\": \00000000\"}' > `rospack find chaplus_ros`/apikey.json")
sys.exit(e)

if self.chatbot_engine=="Chaplus":
self.headers = {'content-type': 'text/json'}
self.url = 'https://www.chaplus.jp/v1/chat?apikey={}'.format(
apikey_json['apikey'])

elif self.chatbot_engine=="A3RT":
self.apikey = apikey_json['apikey_a3rt']
self.endpoint = "https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk"

else:
rospy.logerr("please use chatbot_engine Chaplus or A3RT")
sys.exit(1)

# define pub/sub
self.pub = rospy.Publisher('response', String, queue_size=1)
rospy.Subscriber("request", String, self.topic_cb)

def topic_cb(self, msg):
# use chaplus
if self.chatbot_engine=="Chaplus":
try:
rospy.loginfo("received {}".format(msg.data))
self.data = json.dumps({'utterance': msg.data})
response = requests.post(
url=self.url, headers=self.headers, data=self.data)
response_json = response.json()
if not response_json.has_key('bestResponse'):
best_response = "ごめんなさい、よくわからないです"
else:
best_response = response_json['bestResponse']['utterance']
except Exception as e:
rospy.logerr("Failed to reqeust url={}, headers={}, data={}".format(
self.url, self.headers, self.data))
rospy.logerr(e)
best_response = "ごめんなさい、よくわからないです"
rospy.loginfo("chaplus: returns best response {}".format(best_response))

#use A3RT
elif self.chatbot_engine=="A3RT":
try:
rospy.loginfo("received {}".format(msg.data))
params = {"apikey": self.apikey, "query": msg.data,}
response = requests.post(self.endpoint, params)
response_json = response.json()
if not response_json.has_key('results'):
best_response = "ごめんなさい、よくわからないです"
else:
best_response = response_json["results"][0]["reply"]
except Exception as e:
rospy.logerr("Failed to reqeust url={}, data={}".format(
self.endpoint, msg.data))
rospy.logerr(e)
best_response = "ごめんなさい、よくわからないです"
rospy.loginfo("a3rt: returns best response {}".format(best_response))

else:
rospy.logerr("please use chatbot_engine Chaplus or A3RT")

if response_json is not None:
# convert to string for print out
if sys.version_info.major == 2:
rospy.logdebug(str(json.dumps(response_json, indent=2,
ensure_ascii=False, encoding='unicode-escape')))
else: # pytyon3
rospy.logdebug(json.dumps(
response_json, indent=2, ensure_ascii=False))

#publish response
self.pub.publish(String(best_response))

if __name__ == '__main__':
rospy.init_node('chaplus_ros')
ChaplusROS()
rospy.spin()
13 changes: 13 additions & 0 deletions chaplus_ros/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from setuptools import setup
from catkin_pkg.python_setup import generate_distutils_setup

d = generate_distutils_setup(
# packages=['chaplus_ros'],
# package_dir={'':'src'},
scripts=['scripts/chaplus_ros.py']
)

setup(**d)