Skip to content

Commit d86f665

Browse files
committed
Adds visual output to C++ sample
Bug: 78540198 Change-Id: I26f5f85f0b0e8255b9c7bf641caa8aa0592d13bc
1 parent 7120c5d commit d86f665

File tree

7 files changed

+138
-27
lines changed

7 files changed

+138
-27
lines changed

Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,13 @@ CXXFLAGS += $(ALSA_CFLAGS)
7575
LDFLAGS += $(ALSA_LDFLAGS)
7676
endif
7777

78-
ASSISTANT_O = $(AUDIO_SRCS:.cc=.o) ./src/audio_input_file.o ./src/json_util.o \
78+
ASSISTANT_O = $(AUDIO_SRCS:.cc=.o) ./src/audio_input_file.o ./src/base64_encode.o ./src/json_util.o \
7979
./src/run_assistant_audio.o ./src/run_assistant_text.o
80-
ASSISTANT_AUDIO_O = $(AUDIO_SRCS:.cc=.o) ./src/audio_input_file.o ./src/json_util.o \
80+
ASSISTANT_AUDIO_O = $(AUDIO_SRCS:.cc=.o) ./src/audio_input_file.o ./src/base64_encode.o ./src/json_util.o \
8181
./src/run_assistant_audio.o
82-
ASSISTANT_TEXT_O = ./src/json_util.o ./src/run_assistant_text.o
82+
ASSISTANT_FILE_O = $(AUDIO_SRCS:.cc=.o) ./src/audio_input_file.o ./src/base64_encode.o ./src/json_util.o \
83+
./src/run_assistant_file.o
84+
ASSISTANT_TEXT_O = ./src/json_util.o ./src/base64_encode.o ./src/run_assistant_text.o
8385

8486
.PHONY: all
8587
all: run_assistant
@@ -94,7 +96,7 @@ run_assistant_audio: $(GOOGLEAPIS_ASSISTANT_CCS:.cc=.o) googleapis.ar \
9496
$(CXX) $^ $(LDFLAGS) -o $@
9597

9698
run_assistant_file: $(GOOGLEAPIS_ASSISTANT_CCS:.cc=.o) googleapis.ar \
97-
$(AUDIO_SRCS:.cc=.o) ./src/audio_input_file.o ./src/json_util.o ./src/run_assistant_file.o
99+
$(ASSISTANT_FILE_O)
98100
$(CXX) $^ $(LDFLAGS) -o $@
99101

100102
run_assistant_text: $(GOOGLEAPIS_ASSISTANT_CCS:.cc=.o) googleapis.ar \

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,16 @@ To change the locale, include a `locale` parameter:
113113
echo "Bonjour" | ./run_assistant_text --credentials ./credentials.json --locale "fr-FR"
114114
```
115115

116-
Default Assistant gRPC API endpoint is embeddedassistant.googleapis.com. If you want to test with a custom Assistant gRPC API endpoint, you can pass an extra "--api_endpoint CUSTOM_API_ENDPOINT" to run_assistant.
116+
Default Assistant gRPC API endpoint is `embeddedassistant.googleapis.com`. If you want to test with a custom Assistant gRPC API endpoint, you can pass `--api_endpoint CUSTOM_API_ENDPOINT`.
117+
118+
## Enabling screen output
119+
120+
To get a visual output from the Assistant, provide a command to be run alongside every step of the conversation. It will execute that command along along with a provided argument of a temporary HTML file.
121+
122+
```bash
123+
echo "what time is it" | ./run_assistant_text --credentials ./credentials.json --html_out google-chrome
124+
```
125+
126+
After you enter text, it will run `google-chrome /tmp/google-assistant-cpp-screen-out.html`.
127+
128+
If you prefer a different program, use that argument instead.

src/base64_encode.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Copyright 2017 Google Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#include "base64_encode.h"
18+
19+
// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c by Manuel Martinez
20+
std::string base64_encode(const std::string &in) {
21+
std::string out;
22+
23+
int val=0, valb=-6;
24+
for (u_char c : in) {
25+
val = (val<<8) + c;
26+
valb += 8;
27+
while (valb>=0) {
28+
out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val>>valb)&0x3F]);
29+
valb-=6;
30+
}
31+
}
32+
if (valb>-6) {
33+
out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val<<8)>>(valb+8))&0x3F]);
34+
}
35+
while (out.size()%4) {
36+
out.push_back('=');
37+
}
38+
return out;
39+
}

src/base64_encode.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
Copyright 2018 Google Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
https://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#ifndef BASE64_ENCODE_H
18+
#define BASE64_ENCODE_H
19+
20+
#include <string>
21+
22+
std::string base64_encode(const std::string&);
23+
24+
#endif

src/run_assistant_audio.cc

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,15 @@ limitations under the License.
4242
#include "assistant_config.h"
4343
#include "audio_input.h"
4444
#include "audio_input_file.h"
45+
#include "base64_encode.h"
4546
#include "json_util.h"
4647

4748
using google::assistant::embedded::v1alpha2::EmbeddedAssistant;
4849
using google::assistant::embedded::v1alpha2::AssistRequest;
4950
using google::assistant::embedded::v1alpha2::AssistResponse;
5051
using google::assistant::embedded::v1alpha2::AudioInConfig;
5152
using google::assistant::embedded::v1alpha2::AudioOutConfig;
53+
using google::assistant::embedded::v1alpha2::ScreenOutConfig;
5254
using google::assistant::embedded::v1alpha2::AssistResponse_EventType_END_OF_UTTERANCE;
5355

5456
using grpc::CallCredentials;
@@ -58,11 +60,10 @@ using grpc::ClientReaderWriter;
5860
static const std::string kCredentialsTypeUserAccount = "USER_ACCOUNT";
5961
static const std::string kALSAAudioInput = "ALSA_INPUT";
6062
static const std::string kLanguageCode = "en-US";
61-
static const std::string kDeviceInstanceId = "default";
6263
static const std::string kDeviceModelId = "default";
64+
static const std::string kDeviceInstanceId = "default";
6365

6466
bool verbose = false;
65-
bool use_text = false; // Alternatively use text
6667

6768
// Creates a channel to be connected to Google.
6869
std::shared_ptr<Channel> CreateChannel(const std::string& host) {
@@ -90,24 +91,26 @@ void PrintUsage() {
9091
<< "--credentials <credentials_file> "
9192
<< "[--api_endpoint <API endpoint>] "
9293
<< "[--locale <locale>]"
94+
<< "[--html_out <command to load HTML page>]"
9395
<< std::endl;
9496
}
9597

9698
bool GetCommandLineFlags(
9799
int argc, char** argv, std::string* credentials_file_path,
98-
std::string* api_endpoint, std::string* locale) {
100+
std::string* api_endpoint, std::string* locale, std::string* html_out_command) {
99101
const struct option long_options[] = {
100102
{"credentials", required_argument, nullptr, 'c'},
101103
{"api_endpoint", required_argument, nullptr, 'e'},
102104
{"locale", required_argument, nullptr, 'l'},
103105
{"verbose", no_argument, nullptr, 'v'},
106+
{"html_out", required_argument, nullptr, 'h'},
104107
{nullptr, 0, nullptr, 0}
105108
};
106109
*api_endpoint = ASSISTANT_ENDPOINT;
107110
while (true) {
108111
int option_index;
109112
int option_char =
110-
getopt_long(argc, argv, "c:e:l:v", long_options, &option_index);
113+
getopt_long(argc, argv, "c:e:l:v:h", long_options, &option_index);
111114
if (option_char == -1) {
112115
break;
113116
}
@@ -124,6 +127,9 @@ bool GetCommandLineFlags(
124127
case 'v':
125128
verbose = true;
126129
break;
130+
case 'h':
131+
*html_out_command = optarg;
132+
break;
127133
default:
128134
PrintUsage();
129135
return false;
@@ -133,7 +139,7 @@ bool GetCommandLineFlags(
133139
}
134140

135141
int main(int argc, char** argv) {
136-
std::string credentials_file_path, api_endpoint, locale;
142+
std::string credentials_file_path, api_endpoint, locale, html_out_command;
137143
#ifndef ENABLE_ALSA
138144
std::cerr << "ALSA audio input is not supported on this platform."
139145
<< std::endl;
@@ -144,7 +150,7 @@ int main(int argc, char** argv) {
144150
// https://github.com/grpc/grpc/issues/11366#issuecomment-328595941
145151
grpc_init();
146152
if (!GetCommandLineFlags(argc, argv, &credentials_file_path,
147-
&api_endpoint, &locale)) {
153+
&api_endpoint, &locale, &html_out_command)) {
148154
return -1;
149155
}
150156

@@ -171,6 +177,11 @@ int main(int argc, char** argv) {
171177
AudioOutConfig::LINEAR16);
172178
assist_config->mutable_audio_out_config()->set_sample_rate_hertz(16000);
173179

180+
// Set parameters for screen config
181+
assist_config->mutable_screen_out_config()->set_screen_mode(
182+
html_out_command.empty() ? ScreenOutConfig::SCREEN_MODE_UNSPECIFIED : ScreenOutConfig::PLAYING
183+
);
184+
174185
std::unique_ptr<AudioInput> audio_input;
175186
// Set the AudioInConfig of the AssistRequest
176187
assist_config->mutable_audio_in_config()->set_encoding(
@@ -264,11 +275,16 @@ int main(int argc, char** argv) {
264275
<< ")" << std::endl;
265276
}
266277
}
267-
if (response.dialog_state_out().supplemental_display_text().size() > 0) {
268-
// CUSTOMIZE: render spoken response on screen
269-
std::clog << "assistant_sdk response:" << std::endl;
270-
std::cout << response.dialog_state_out().supplemental_display_text()
271-
<< std::endl;
278+
if (!html_out_command.empty() && response.screen_out().data().size() > 0) {
279+
std::string html_out_base64 = base64_encode(response.screen_out().data());
280+
system((html_out_command + " \"data:text/html;base64, " + html_out_base64 + "\"").c_str());
281+
} else if (html_out_command.empty()) {
282+
if (response.dialog_state_out().supplemental_display_text().size() > 0) {
283+
// CUSTOMIZE: render spoken response on screen
284+
std::clog << "assistant_sdk response:" << std::endl;
285+
std::cout << response.dialog_state_out().supplemental_display_text()
286+
<< std::endl;
287+
}
272288
}
273289
}
274290

src/run_assistant_file.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ limitations under the License.
3434
#include "assistant_config.h"
3535
#include "audio_input.h"
3636
#include "audio_input_file.h"
37+
#include "base64_encode.h"
3738
#include "json_util.h"
3839

3940
using google::assistant::embedded::v1alpha2::EmbeddedAssistant;
@@ -49,8 +50,8 @@ using grpc::ClientReaderWriter;
4950

5051
static const std::string kCredentialsTypeUserAccount = "USER_ACCOUNT";
5152
static const std::string kLanguageCode = "en-US";
52-
static const std::string kDeviceInstanceId = "default";
5353
static const std::string kDeviceModelId = "default";
54+
static const std::string kDeviceInstanceId = "default";
5455

5556
bool verbose = false;
5657

src/run_assistant_text.cc

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ limitations under the License.
3434
#include "assistant_config.h"
3535
#include "audio_input.h"
3636
#include "audio_input_file.h"
37+
#include "base64_encode.h"
3738
#include "json_util.h"
3839

3940
using google::assistant::embedded::v1alpha2::EmbeddedAssistant;
4041
using google::assistant::embedded::v1alpha2::AssistRequest;
4142
using google::assistant::embedded::v1alpha2::AssistResponse;
4243
using google::assistant::embedded::v1alpha2::AudioInConfig;
4344
using google::assistant::embedded::v1alpha2::AudioOutConfig;
45+
using google::assistant::embedded::v1alpha2::ScreenOutConfig;
4446
using google::assistant::embedded::v1alpha2::AssistResponse_EventType_END_OF_UTTERANCE;
4547

4648
using grpc::CallCredentials;
@@ -49,8 +51,8 @@ using grpc::ClientReaderWriter;
4951

5052
static const std::string kCredentialsTypeUserAccount = "USER_ACCOUNT";
5153
static const std::string kLanguageCode = "en-US";
52-
static const std::string kDeviceInstanceId = "default";
5354
static const std::string kDeviceModelId = "default";
55+
static const std::string kDeviceInstanceId = "default";
5456

5557
bool verbose = false;
5658

@@ -80,24 +82,26 @@ void PrintUsage() {
8082
<< "--credentials <credentials_file> "
8183
<< "[--api_endpoint <API endpoint>] "
8284
<< "[--locale <locale>]"
85+
<< "[--html_out <command to load HTML file>]"
8386
<< std::endl;
8487
}
8588

8689
bool GetCommandLineFlags(
8790
int argc, char** argv, std::string* credentials_file_path,
88-
std::string* api_endpoint, std::string* locale) {
91+
std::string* api_endpoint, std::string* locale, std::string* html_out_command) {
8992
const struct option long_options[] = {
9093
{"credentials", required_argument, nullptr, 'c'},
9194
{"api_endpoint", required_argument, nullptr, 'e'},
9295
{"locale", required_argument, nullptr, 'l'},
9396
{"verbose", no_argument, nullptr, 'v'},
97+
{"html_out", required_argument, nullptr, 'h'},
9498
{nullptr, 0, nullptr, 0}
9599
};
96100
*api_endpoint = ASSISTANT_ENDPOINT;
97101
while (true) {
98102
int option_index;
99103
int option_char =
100-
getopt_long(argc, argv, "c:e:l:v", long_options, &option_index);
104+
getopt_long(argc, argv, "c:e:l:v:h", long_options, &option_index);
101105
if (option_char == -1) {
102106
break;
103107
}
@@ -114,6 +118,9 @@ bool GetCommandLineFlags(
114118
case 'v':
115119
verbose = true;
116120
break;
121+
case 'h':
122+
*html_out_command = optarg;
123+
break;
117124
default:
118125
PrintUsage();
119126
return false;
@@ -123,12 +130,12 @@ bool GetCommandLineFlags(
123130
}
124131

125132
int main(int argc, char** argv) {
126-
std::string credentials_file_path, api_endpoint, locale, text_input_source;
133+
std::string credentials_file_path, api_endpoint, locale, text_input_source, html_out_command;
127134
// Initialize gRPC and DNS resolvers
128135
// https://github.com/grpc/grpc/issues/11366#issuecomment-328595941
129136
grpc_init();
130137
if (!GetCommandLineFlags(argc, argv, &credentials_file_path,
131-
&api_endpoint, &locale)) {
138+
&api_endpoint, &locale, &html_out_command)) {
132139
return -1;
133140
}
134141

@@ -156,6 +163,11 @@ int main(int argc, char** argv) {
156163
assist_config->mutable_audio_out_config()->set_sample_rate_hertz(16000);
157164
assist_config->set_text_query(text_input_source);
158165

166+
// Set parameters for screen config
167+
assist_config->mutable_screen_out_config()->set_screen_mode(
168+
html_out_command.empty() ? ScreenOutConfig::SCREEN_MODE_UNSPECIFIED : ScreenOutConfig::PLAYING
169+
);
170+
159171
// Read credentials file.
160172
std::ifstream credentials_file(credentials_file_path);
161173
if (!credentials_file) {
@@ -210,11 +222,16 @@ int main(int argc, char** argv) {
210222
<< ")" << std::endl;
211223
}
212224
}
213-
if (response.dialog_state_out().supplemental_display_text().size() > 0) {
214-
// CUSTOMIZE: render spoken response on screen
215-
std::clog << "assistant_sdk response:" << std::endl;
216-
std::cout << response.dialog_state_out().supplemental_display_text()
217-
<< std::endl;
225+
if (!html_out_command.empty() && response.screen_out().data().size() > 0) {
226+
std::string html_out_base64 = base64_encode(response.screen_out().data());
227+
system((html_out_command + " \"data:text/html;base64, " + html_out_base64 + "\"").c_str());
228+
} else if (html_out_command.empty()) {
229+
if (response.dialog_state_out().supplemental_display_text().size() > 0) {
230+
// CUSTOMIZE: render spoken response on screen
231+
std::clog << "assistant_sdk response:" << std::endl;
232+
std::cout << response.dialog_state_out().supplemental_display_text()
233+
<< std::endl;
234+
}
218235
}
219236
}
220237

0 commit comments

Comments
 (0)