speech
Loading...
Searching...
No Matches
main.cpp
1/*
2 * Copyright (C) 2018 iCub Facility - Istituto Italiano di Tecnologia
3 * Author: Ilaria Carlini Laura Cavaliere Vadim Tikhanoff
4 * email: ilaria.carlini@iit.it laura.cavaliere@iit.it vadim.tikhanoff@iit.it
5 * Permission is granted to copy, distribute, and/or modify this program
6 * under the terms of the GNU General Public License, version 2 or any
7 * later version published by the Free Software Foundation.
8 *
9 * A copy of the license can be found at
10 * http://www.robotcub.org/icub/license/gpl.txt
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 * Public License for more details
16 */
17
18#include <vector>
19#include <iostream>
20#include <deque>
21#include <cstdio>
22#include <cmath>
23
24#include <fstream>
25#include <iterator>
26#include <string>
27#include <map>
28
29#include <yarp/os/BufferedPort.h>
30#include <yarp/os/ResourceFinder.h>
31#include <yarp/os/RFModule.h>
32#include <yarp/os/Network.h>
33#include <yarp/os/Time.h>
34#include <yarp/os/Log.h>
35#include <yarp/os/LogStream.h>
36#include <yarp/os/Semaphore.h>
37#include <yarp/sig/SoundFile.h>
38#include <yarp/dev/PolyDriver.h>
39
40#include <grpc++/grpc++.h>
41#include "google/cloud/language/v1/language_service.grpc.pb.h"
42#include "google/cloud/texttospeech/v1/cloud_tts.grpc.pb.h"
43#include "google/cloud/dialogflow/cx/v3beta1/agent.grpc.pb.h"
44#include "google/cloud/dialogflow/cx/v3beta1/audio_config.grpc.pb.h"
45//#include "google/cloud/dialogflow/cx/v3beta1/context.grpc.pb.h"
46#include "google/cloud/dialogflow/cx/v3beta1/entity_type.grpc.pb.h"
47#include "google/cloud/dialogflow/cx/v3beta1/intent.grpc.pb.h"
48#include "google/cloud/dialogflow/cx/v3beta1/session_entity_type.grpc.pb.h"
49#include "google/cloud/dialogflow/cx/v3beta1/session.grpc.pb.h"
50#include "google/cloud/dialogflow/cx/v3beta1/webhook.grpc.pb.h"
51
52#include <chrono>
53#include <ctime>
54#include <algorithm>
55
56#include "googleDialog_IDL.h"
57
58using namespace google::cloud::language::v1;
59using namespace google::cloud::texttospeech::v1;
60using namespace google::cloud::dialogflow::cx::v3beta1;
61bool is_changed;
62
63static const std::map<grpc::StatusCode, std::string> status_code_to_string {
64 {grpc::OK, "ok"},
65 {grpc::CANCELLED, "cancelled"},
66 {grpc::UNKNOWN, "unknown"},
67 {grpc::INVALID_ARGUMENT, "invalid_argument"},
68 {grpc::DEADLINE_EXCEEDED, "deadline_exceeded"},
69 {grpc::NOT_FOUND, "not_found"},
70 {grpc::ALREADY_EXISTS, "already_exists"},
71 {grpc::PERMISSION_DENIED, "permission_denied"},
72 {grpc::UNAUTHENTICATED, "unauthenticated"},
73 {grpc::RESOURCE_EXHAUSTED , "resource_exhausted"},
74 {grpc::FAILED_PRECONDITION, "failed_precondition"},
75 {grpc::ABORTED, "aborted"},
76 {grpc::OUT_OF_RANGE, "out_of_range"},
77 {grpc::UNIMPLEMENTED, "unimplemented"},
78 {grpc::INTERNAL, "internal"},
79 {grpc::UNAVAILABLE, "unavailable"},
80 {grpc::DATA_LOSS, "data_loss"},
81 {grpc::DO_NOT_USE, "do_not_use"}
82};
83/********************************************************/
84class Processing : public yarp::os::BufferedPort<yarp::os::Bottle>
85{
86 std::string moduleName;
87 std::string session_id;
88 std::string agent_name;
89 std::string language_code;
90 std::string &state;
91 bool &input_is_empty, reset;
92 std::int64_t &processing_time;
93 yarp::os::RpcServer handlerPort;
94 yarp::os::BufferedPort<yarp::os::Bottle> targetPort;
95
96public:
97 /********************************************************/
98
99 Processing( const std::string &moduleName, const std::string agent_name, const std::string language_code, std::string &state, bool &input_is_empty, std::int64_t &processing_time) : state(state), input_is_empty(input_is_empty), processing_time(processing_time)
100 {
101 this->moduleName = moduleName;
102 this->session_id = getRandSession();
103 this->agent_name = agent_name;
104 this->language_code = language_code;
105 reset = false;
106 yInfo()<< "State: " << state;
107 yInfo()<< "input_is_empty: " << input_is_empty;
108 }
109
110 /********************************************************/
111 ~Processing()
112 {
113
114 };
115 /********************************************************/
116 std::string getRandSession() {
117 std::string session;
118 srand(time(NULL));
119 for(int i = 0; i<16; i++) {
120 session += std::to_string(rand() % 10);
121 }
122 return session;
123 }
124 /********************************************************/
125 bool open()
126 {
127 this->useCallback();
128 yarp::os::BufferedPort<yarp::os::Bottle >::open( "/" + moduleName + "/text:i" );
129 targetPort.open("/"+ moduleName + "/result:o");
130
131 return true;
132 }
133
134 /********************************************************/
135 void close()
136 {
137 yarp::os::BufferedPort<yarp::os::Bottle >::close();
138 targetPort.close();
139 }
140
141 /********************************************************/
142 void onRead( yarp::os::Bottle &bot)
143 {
144 yarp::os::Bottle &outTargets = targetPort.prepare();
145
146 outTargets.clear();
147 outTargets = queryGoogleDialog(bot);
148 yDebug() << "bottle" << outTargets.toString();
149 if(outTargets.size()>0){
150 targetPort.write();
151 }
152 yInfo() << "State: " << state;
153 yDebug() << "done querying google";
154 }
155
156/********************************************************/
157 yarp::os::Bottle queryGoogleDialog(yarp::os::Bottle& bottle)
158 {
159 std::string text = bottle.toString();
160 yarp::os::Bottle result;
161 google::cloud::dialogflow::cx::v3beta1::TextInput text_input;
162 google::cloud::dialogflow::cx::v3beta1::QueryInput query_input;
163
164 //std::string language_code = "en-English";
165 text_input.set_text(text.c_str());
166 query_input.set_allocated_text(&text_input);
167 query_input.set_language_code(language_code);
168
169 grpc::Status status;
170 grpc::ClientContext context;
171
172 DetectIntentRequest request;
173 DetectIntentResponse response;
174
175 request.set_session(agent_name+"/environments/draft/sessions/"+session_id);
176 request.set_allocated_query_input(&query_input);
177 std::string user_express = request.query_input().text().text();
178 yInfo() << "End-user expression:" << user_express;
179 if(request.query_input().text().text().size()>0){
180 input_is_empty=false;
181 auto creds = grpc::GoogleDefaultCredentials();
182 auto channel = grpc::CreateChannel("dialogflow.googleapis.com", creds);
183 std::unique_ptr<Sessions::Stub> dialog (Sessions::NewStub(channel));
184 checkState("Busy");
185 yarp::os::Time::delay(0.2);
186 const std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::steady_clock::now();
187
188 grpc::Status dialog_status = dialog->DetectIntent(&context, request, &response);
189 std::string status_string = status_code_to_string.at(dialog_status.error_code());
190
191 result.clear();
192 if ( dialog_status.ok() ) {
193 const auto end = std::chrono::steady_clock::now();
194 processing_time = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
195 yDebug() << "Request processing time: " << processing_time << "µs";
196
197 yInfo() << "Status returned OK";
198 yInfo() << "\n------Response------\n";
199 if (response.query_result().response_messages().size() > 0 && response.query_result().response_messages().Get(0).text().text().size() > 0)
200 {
201 result.addString(response.query_result().response_messages().Get(0).text().text().Get(0).c_str());
202 yDebug() << "result bottle" << result.toString();
203 checkState("Done");
204 }
205 else if (reset)
206 {
207 checkState("Reset");
208 reset=false;
209 }
210 else
211 {
212 checkState("Empty");
213 }
214 }
215 else if ( !dialog_status.ok() ) {
216 yError() << "Status Returned Cancelled";
217 checkState("Failure_" + status_string);
218 yInfo() << dialog_status.error_message();
219 }
220 }
221 else if (request.query_input().text().text().size()==0){
222 input_is_empty=true;
223 yError() << "Input is empty";
224 }
225 request.release_query_input();
226 query_input.release_text();
227 return result;
228 }
229
230 /********************************************************/
231 bool setLanguageCode(const std::string &languageCode)
232 {
233 language_code = languageCode;
234 return true;
235 }
236
237 /********************************************************/
238 std::string getLanguageCode()
239 {
240 return language_code;
241 }
242
243 /********************************************************/
244 bool start_acquisition()
245 {
246 return true;
247 }
248
249 /********************************************************/
250 bool stop_acquisition()
251 {
252 return true;
253 }
254
255 /********************************************************/
256 bool checkState(std::string new_state)
257 {
258 if(new_state!=state){
259 is_changed=true;
260 state=new_state;
261 }
262 else{
263 is_changed=false;
264 }
265 return is_changed;
266 }
267
268 /********************************************************/
269 void resetDialog(){
270 reset = true;
271 yarp::os::Bottle bot;
272 bot.clear();
273 bot.addString("Exit");
274 queryGoogleDialog(bot);
275 }
276};
277
278/********************************************************/
279class Module : public yarp::os::RFModule, public googleDialog_IDL
280{
281 yarp::os::ResourceFinder *rf;
282 yarp::os::RpcServer rpcPort;
283 std::string state;
284 std::int64_t processing_time;
285 bool input_is_empty;
286 yarp::os::BufferedPort<yarp::os::Bottle> statePort;
287
288 Processing *processing;
289 friend class processing;
290
291 bool closing;
292 std::vector<std::string> allLanguageCodes;
293
294 /********************************************************/
295 bool attach(yarp::os::RpcServer &source)
296 {
297 return this->yarp().attachAsServer(source);
298 }
299
300public:
301
302 /********************************************************/
303 bool configure(yarp::os::ResourceFinder &rf)
304 {
305 this->rf=&rf;
306 this->state="Ready";
307 this->input_is_empty=false;
308 this->processing_time=0;
309 std::string moduleName = rf.check("name", yarp::os::Value("googleDialog"), "module name (string)").asString();
310 std::string agent_name = rf.check("agent", yarp::os::Value("1"), "name of the agent").asString();
311 std::string language_code = rf.check("language", yarp::os::Value("en-US"), "language of the dialogflow").asString();
312
313 if (rf.check("languageCodes", "Getting language codes"))
314 {
315 yarp::os::Bottle &grp=rf.findGroup("languageCodes");
316 int sz=grp.size()-1;
317
318 for (int i=0; i<sz; i++)
319 allLanguageCodes.push_back(grp.get(1+i).asString());
320 }
321
322 yDebug() << "this is the project" << rf.check("project");
323 yDebug() << "Module name" << moduleName;
324 yDebug() << "agent name" << agent_name;
325 yDebug() << "language of the dialog" << language_code;
326 setName(moduleName.c_str());
327
328 rpcPort.open(("/"+getName("/rpc")).c_str());
329 statePort.open("/"+ moduleName + "/state:o");
330
331 closing = false;
332
333 processing = new Processing( moduleName, agent_name, language_code, state, input_is_empty, processing_time);
334
335 /* now start the thread to do the work */
336 processing->open();
337
338 attach(rpcPort);
339
340 return true;
341 }
342
343 /********************************************************/
344 bool setLanguage(const std::string& languageCode)
345 {
346 bool returnVal = false;
347
348 std::string language;
349
350 for (int i = 0; i < allLanguageCodes.size(); i++)
351 {
352 if (languageCode == allLanguageCodes[i])
353 {
354 language = languageCode;
355 processing->setLanguageCode(languageCode);
356 returnVal = true;
357 break;
358 }
359 }
360
361 return returnVal;
362 }
363
364 /********************************************************/
365 std::string getLanguageCode()
366 {
367 return processing->getLanguageCode();
368 }
369
370 /**********************************************************/
371 bool close()
372 {
373 statePort.close();
374 processing->close();
375 delete processing;
376 return true;
377 }
378
379 /********************************************************/
380 double getPeriod()
381 {
382 return 0.1;
383 }
384
385 /********************************************************/
386 bool quit()
387 {
388 closing=true;
389 return true;
390 }
391
392 /********************************************************/
393 bool updateModule()
394 {
395 if(is_changed){
396 is_changed=false;
397 yarp::os::Bottle &outTargets = statePort.prepare();
398 outTargets.clear();
399 outTargets.addString(state);
400 yDebug() << "outTarget:" << outTargets.toString().c_str();
401 statePort.write();
402 }
403 return !closing;
404 }
405
406 /********************************************************/
407 std::string getState()
408 {
409 return state;
410 }
411
412 /********************************************************/
413 std::int64_t getProcessingTime()
414 {
415 return processing_time;
416 }
417
418 /********************************************************/
419 bool resetDialog()
420 {
421 processing->resetDialog();
422 return true;
423 }
424};
425
426/********************************************************/
427int main(int argc, char *argv[])
428{
429 yarp::os::Network::init();
430
431 yarp::os::Network yarp;
432 if (!yarp.checkNetwork())
433 {
434 yError("YARP server not available!");
435 return 1;
436 }
437
438 Module module;
439 yarp::os::ResourceFinder rf;
440
441 rf.setVerbose( true );
442 rf.setDefaultContext( "googleDialog" );
443 rf.setDefaultConfigFile( "config.ini" );
444 rf.setDefault("name","googleDialog");
445 rf.configure(argc,argv);
446
447 return module.runModule(rf);
448}