Skip to content

Commit

Permalink
[WIP] GoogleDialogFlowCxChatBot - first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
elandini84 committed Sep 19, 2023
1 parent 2624697 commit 88617c0
Show file tree
Hide file tree
Showing 6 changed files with 389 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/devices/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
# SPDX-License-Identifier: BSD-3-Clause

add_subdirectory(googleSpeechSynthesizer)
add_subdirectory(googleDialogflowCxChatBot)
45 changes: 45 additions & 0 deletions src/devices/googleDialogflowCxChatBot/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
# SPDX-License-Identifier: BSD-3-Clause

yarp_prepare_plugin(googleDialogFlowCxChatBot
CATEGORY device
TYPE GoogleDialogFlowCxChatBot
INCLUDE GoogleDialogFlowCxChatBot.h
INTERNAL ON
)

find_package(google_cloud_cpp_dialogflow_cx REQUIRED)

if(NOT SKIP_googleDialogFlowCxChatBot)
yarp_add_plugin(yarp_googleDialogFlowCxChatBot)

target_sources(yarp_googleDialogFlowCxChatBot
PRIVATE
GoogleDialogFlowCxChatBot.cpp
GoogleDialogFlowCxChatBot.h
)

target_link_libraries(yarp_googleDialogFlowCxChatBot
PRIVATE
YARP::YARP_os
YARP::YARP_sig
YARP::YARP_dev
google-cloud-cpp::dialogflow_cx
)

yarp_install(
TARGETS yarp_googleDialogFlowCxChatBot
EXPORT yarp-device-googleDialogFlowCxChatBot
COMPONENT yarp-device-googleDialogFlowCxChatBot
LIBRARY DESTINATION ${YARP_DYNAMIC_PLUGINS_INSTALL_DIR}
ARCHIVE DESTINATION ${YARP_STATIC_PLUGINS_INSTALL_DIR}
YARP_INI DESTINATION ${YARP_PLUGIN_MANIFESTS_INSTALL_DIR}
)

if(YARP_COMPILE_TESTS)
add_subdirectory(tests)
add_subdirectory(demos)
endif()

set_property(TARGET yarp_googleDialogFlowCxChatBot PROPERTY FOLDER "Plugins/Device")
endif()
100 changes: 100 additions & 0 deletions src/devices/googleDialogflowCxChatBot/GoogleDialogFlowCxChatBot.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif

#include "GoogleDialogFlowCxChatBot.h"

#include <yarp/sig/SoundFile.h>

#include <yarp/os/LogComponent.h>
#include <yarp/os/LogStream.h>
#include <fstream>

#include <cmath>

using namespace yarp::os;
using namespace yarp::dev;


YARP_LOG_COMPONENT(GOOGLEDIALOGFLOWCXBOT, "yarp.googleDialogFlowCxChatBot", yarp::os::Log::TraceType);


bool GoogleDialogFlowCxChatBot::open(yarp::os::Searchable &config)
{
yCDebug(GOOGLEDIALOGFLOWCXBOT) << "Configuration: \n" << config.toString().c_str();

if(!config.check("project"))
{
yCError(GOOGLEDIALOGFLOWCXBOT) << "project parameter must be specified";
return false;
}
m_project = config.find("project").asString();

if(!config.check("location"))
{
yCError(GOOGLEDIALOGFLOWCXBOT) << "location parameter must be specified";
return false;
}
m_location = config.find("location").asString();

if(!config.check("display_name"))
{
yCError(GOOGLEDIALOGFLOWCXBOT) << "display_name parameter must be specified";
return false;
}
std::string displayName = config.find("display_name").asString();

auto agentsClient = std::make_shared<google::cloud::dialogflow_cx::AgentsClient>(google::cloud::dialogflow_cx::MakeAgentsConnection(m_location));
google::cloud::dialogflow::cx::v3::ListAgentsRequest request;
std::string parent = "projects/"+m_project;
request.set_parent(parent);
google::cloud::v2_15::StreamRange<google::cloud::dialogflow::cx::v3::Agent> agentsList = agentsClient->ListAgents(request);

// Cerca l'agente con il display name specificato.
for (const auto& agent : agentsList) {
if (agent->display_name() == displayName) {
m_agentId = agent->name();
break;
}
}

//m_session = std::make_shared<google::cloud::dialogflow_cx::SessionsClient>(google::cloud::dialog);
return true;
}

bool GoogleDialogFlowCxChatBot::close()
{
return true;
}

bool GoogleDialogFlowCxChatBot::interact(const std::string& messageIn, std::string& messageOut)
{
YARP_UNUSED(messageIn);
YARP_UNUSED(messageOut);
google::cloud::dialogflow::cx::v3::DetectIntentRequest req;


return true;
}

bool GoogleDialogFlowCxChatBot::setLanguage(const std::string& language)
{
YARP_UNUSED(language);
return true;
}

bool GoogleDialogFlowCxChatBot::getLanguage(std::string& language)
{
YARP_UNUSED(language);
return true;
}

bool GoogleDialogFlowCxChatBot::resetBot()
{
return true;
}
158 changes: 158 additions & 0 deletions src/devices/googleDialogflowCxChatBot/GoogleDialogFlowCxChatBot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
* SPDX-License-Identifier: BSD-3-Clause
*/

#ifndef YARP_GOOGLEDIALOGCXBOT_H
#define YARP_GOOGLEDIALOGCXBOT_H

#include <yarp/dev/DeviceDriver.h>
#include <yarp/dev/IChatBot.h>
#include <yarp/os/Network.h>
#include <algorithm>

#include <google/cloud/dialogflow_cx/agents_client.h>
#include <google/cloud/dialogflow/cx/v3/agent.pb.h>
#include <google/cloud/dialogflow_cx/sessions_client.h>
#include <google/cloud/dialogflow/cx/v3/session.grpc.pb.h>
#include <google/cloud/dialogflow/cx/v3/session.pb.h>
#include <grpcpp/grpcpp.h>

/**
* @ingroup dev_impl_other
*
* \section googleDialogFlowCxChatBot
*
* \brief `googleDialogFlowCxChatBot`: A yarp device to enable interaction with Google's DialogFlow CX service
*
* Parameters required by this device are:
* | Parameter name | SubParameter | Type | Units | Default Value | Required | Description | Notes |
* |:--------------:|:------------:|:-------:|:--------------:|:-------------:|:--------:|:----------------------------------------------------------------:|:-----:|
* | project | - | string | - | - | Yes | The name of the Google cloud project the wanted agent belongs to | |
* | location | - | string | - | - | Yes | The world region specified for the wanted agent | |
* | display_name | - | string | - | - | Yes | The human readable name of the agent | |
*
*
* example of xml file with a fake odometer
*
* \code{.unparsed}
* <?xml version="1.0" encoding="UTF-8"?>
* <!DOCTYPE robot PUBLIC "-//YARP//DTD yarprobotinterface 3.0//EN" "http://www.yarp.it/DTD/yarprobotinterfaceV3.0.dtd">
* <robot name="googleTest" build="2" portprefix="/googleSynth" xmlns:xi="http://www.w3.org/2001/XInclude">
* <devices>
* <device name="googleDialogCx" type="googleDialogFlowCxChatBot">
* <param name="project">
* hsp-speech-interaction-dev
* </param>
* <param name="location">
* global
* </param>
* <param name="display_name">
* HSP_Agent_Object_retrieval
* </param>
* </device>
*
* <device name="dialogWrap" type="chatBot_nws_yarp">
* <action phase="startup" level="5" type="attach">
* <paramlist name="networks">
* <elem name="subdeviceGoogle">
* googleSynth
* </elem>
* </paramlist>
* </action>
* <action phase="shutdown" level="5" type="detach" />
* </device>
* </devices>
* </robot>
* \endcode
*/




/*
```cpp
#include <iostream>
#include <google/cloud/dialogflow/cx/v3/sessions.grpc.pb.h>
#include <google/cloud/dialogflow/cx/v3/sessions.pb.h>
#include <grpcpp/grpcpp.h>
using namespace google::cloud::dialogflow::cx::v3;
int main() {
// Initialize the gRPC channel with your Dialogflow CX API endpoint.
std::shared_ptr<grpc::Channel> channel = grpc::CreateChannel("YOUR_API_ENDPOINT", grpc::GoogleDefaultCredentials());
// Create a session client.
Sessions::Stub stub(channel);
// Set your Dialogflow CX project ID and session ID.
std::string project_id = "YOUR_PROJECT_ID";
std::string location_id = "YOUR_LOCATION_ID"; // The location ID of your agent
std::string agent_id = "YOUR_AGENT_ID"; // The ID of your agent
std::string session_id = "YOUR_SESSION_ID";
// Create a session name.
SessionName session_name(project_id, location_id, agent_id, session_id);
// Create a query input.
TextInput text_input;
text_input.set_text("Hello, chatbot!");
// Create a query parameters.
QueryParameters query_parameters;
// Create a detect intent request.
DetectIntentRequest request;
request.set_session(session_name.ToString());
*request.mutable_query_input()->mutable_text() = text_input;
*request.mutable_query_params() = query_parameters;
// Send the request to Dialogflow CX.
DetectIntentResponse response;
grpc::Status status = stub.DetectIntent(&request, &response);
if (status.ok()) {
std::cout << "Response: " << response.query_result().response_messages(0).text().text() << std::endl;
} else {
std::cerr << "Error: " << status.error_message() << std::endl;
}
return 0;
}
```
*/



class GoogleDialogFlowCxChatBot :
public yarp::dev::DeviceDriver,
public yarp::dev::IChatBot
{
public:
GoogleDialogFlowCxChatBot() = default;
GoogleDialogFlowCxChatBot(const GoogleDialogFlowCxChatBot&) = delete;
GoogleDialogFlowCxChatBot(GoogleDialogFlowCxChatBot&&) noexcept = delete;
GoogleDialogFlowCxChatBot& operator=(const GoogleDialogFlowCxChatBot&) = delete;
GoogleDialogFlowCxChatBot& operator=(GoogleDialogFlowCxChatBot&&) noexcept = delete;
~GoogleDialogFlowCxChatBot() override = default;

// DeviceDriver
bool open(yarp::os::Searchable& config) override;
bool close() override;

// IChatBot
bool interact(const std::string& messageIn, std::string& messageOut) override;
bool setLanguage(const std::string& language) override;
bool getLanguage(std::string& language) override;
bool resetBot() override;

private:
std::string m_project;
std::string m_region;
std::string m_location;
std::string m_agentId;
std::shared_ptr<google::cloud::dialogflow_cx::SessionsClient> m_session{nullptr};
};

#endif // YARP_GOOGLEDIALOGCXBOT_H
4 changes: 4 additions & 0 deletions src/devices/googleDialogflowCxChatBot/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
# SPDX-License-Identifier: BSD-3-Clause

create_device_test (googleDialogFlowCxChatBot)
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <yarp/dev/ISpeechSynthesizer.h>
#include <yarp/os/Network.h>
#include <yarp/os/LogStream.h>
#include <yarp/os/ResourceFinder.h>
#include <yarp/dev/PolyDriver.h>
#include <yarp/dev/WrapperSingle.h>

#include <yarp/sig/Sound.h>
#include <yarp/sig/SoundFile.h>

#include <catch2/catch_amalgamated.hpp>
#include <harness.h>

using namespace yarp::dev;
using namespace yarp::os;

TEST_CASE("dev::googleDialogFlowCxChatBot_test", "[yarp::dev]")
{
YARP_REQUIRE_PLUGIN("googleDialogFlowCxChatBot", "device");

Network::setLocalMode(true);

SECTION("Checking googleDialogFlowCxChatBot device")
{
ISpeechSynthesizer* iSynth{nullptr};
PolyDriver dd;

//read a test sound file from disk
yarp::sig::Sound snd;
yarp::os::ResourceFinder rf;

rf.setQuiet(false);
rf.setVerbose(true);

rf.setDefaultContext("googleDialogFlowCxChatBot_demo");
std::string ss = rf.findFile("test_audio.wav");
CHECK(!ss.empty());
yarp::sig::file::read(snd,ss.c_str());
CHECK(snd.getSamples()>0);

//"Checking opening device"
{
Property pcfg;
const std::string init_lang{"it-IT"};
const std::string init_voice{"it-IT-Wavenet-A"};
pcfg.put("device", "googleDialogFlowCxChatBot");
pcfg.put("language_code",init_lang);
pcfg.put("voice_name",init_voice);
REQUIRE(dd.open(pcfg));
REQUIRE(dd.view(iSynth));
}

const std::string lang_to_set{"en-GB"};
const std::string voice_to_set{"en-GB-Neural2-C"};
std::string lang_code;
std::string voice_name;

std::string toSynthesize{"This is a text to speech test"};
yarp::sig::Sound outputSound;
CHECK(iSynth->setLanguage(lang_to_set));
CHECK(iSynth->setVoice(voice_to_set));
CHECK(iSynth->getLanguage(lang_code));
CHECK(lang_code == lang_to_set);
CHECK(iSynth->getVoice(voice_name));
CHECK(voice_name == voice_to_set);
CHECK(iSynth->synthesize(toSynthesize,outputSound));
CHECK(outputSound == snd);

//"Close all polydrivers and check"
{
CHECK(dd.close());
}
}

Network::setLocalMode(false);
}

0 comments on commit 88617c0

Please sign in to comment.