forked from aws-samples/aws-lex-web-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathupdate-lex-web-ui-config.js
277 lines (267 loc) · 9.26 KB
/
update-lex-web-ui-config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/**
* Updates config files used by the build environment
* It merges the values from the environment with the
* existing values in the config files.
* Values from the environment take precendence.
*
* This is called during the build process by
* the Makefile in the root dir which is run by CodeBuild
*/
const fs = require('fs');
const config = require('../config');
const {exec} = require("child_process");
const path = require("path");
let revisedConfig;
/**
* lexV2BotLocaleVoices maps lex v2 locale IDs to support voices to be used when creating initial speech mp3 files.
* The mapping identifies a voiceId, an engine, and a languageCode to use when executing aws polly CLI. Over time
* the set of supported localeId to Voices may be expanded. An empty string for a languageCode indicates that polly
* does not support a language code for this locale.
*/
const lexV2BotLocaleVoices = {
"de_AT": {
"voiceId": "Vicki",
"engine": "neural",
"languageCode": "de-AT"
},
"de_DE": {
"voiceId": "Vicki",
"engine": "neural",
"languageCode": "de-DE"
},
"en_AU": {
"voiceId": "Olivia",
"engine": "neural",
"languageCode": "en-AU"
},
"en_GB": {
"voiceId": "Amy",
"engine": "neural",
"languageCode": "en-GB"
},
"en_IN": {
"voiceId": "Aditi",
"engine": "standard",
"languageCode": "en-IN"
},
"en_US": {
"voiceId": "Joanna",
"engine": "neural",
"languageCode": "en-US"
},
"en_ZA": {
"voiceId": "Ayanda",
"engine": "neural",
"languageCode": "en-ZA"
},
"es_419": {
"voiceId": "Mia",
"engine": "standard",
"languageCode": ""
},
"es_ES": {
"voiceId": "Lucia",
"engine": "neural",
"languageCode": "es-ES"
},
"es_US": {
"voiceId": "Lupe",
"engine": "neural",
"languageCode": "es-US"
},
"fr_CA": {
"voiceId": "Gabrielle",
"engine": "neural",
"languageCode": "fr-CA"
},
"fr_FR": {
"voiceId": "Lea",
"engine": "neural",
"languageCode": "fr-FR"
},
"it_IT": {
"voiceId": "Bianca",
"engine": "neural",
"languageCode": "it-IT"
},
"ja_JP": {
"voiceId": "Takumi",
"engine": "neural",
"languageCode": "ja-JP"
},
"ko_KR": {
"voiceId": "Seoyeon",
"engine": "neural",
"languageCode": "ko-KR"
},
"pt_BR": {
"voiceId": "Camila",
"engine": "neural",
"languageCode": ""
},
"pt_PT": {
"voiceId": "Cristiano",
"engine": "standard",
"languageCode": "pt-PT"
},
"zh_CN": {
"voiceId": "Zhiyu",
"engine": "standard",
"languageCode": ""
}
};
// dump relevant env vars
[
'AWS_DEFAULT_REGION',
'V2_BOT_ID',
'V2_BOT_ALIAS_ID',
'V2_BOT_LOCALE_ID',
'BOT_NAME',
'BOT_ALIAS',
'BOT_INITIAL_TEXT',
'BOT_INITIAL_SPEECH',
'BOT_INITIAL_UTTERANCE',
'BOT_RETRY_ON_LEX_POST_TEXT_TIMEOUT',
'BOT_RETRY_COUNT_POST_TEXT_TIMEOUT',
'IFRAME_ORIGIN',
'PARENT_ORIGIN',
'ENABLE_LOGIN',
'ENABLE_LIVE_CHAT',
'FORCE_LOGIN',
'POOL_ID',
'APP_USER_POOL_CLIENT_ID',
'CONNECT_CONTACT_FLOW_ID',
'CONNECT_INSTANCE_ID',
'CONNECT_API_GATEWAY_ENDPOINT',
'CONNECT_PROMPT_FOR_NAME_MESSAGE',
'CONNECT_WAIT_FOR_AGENT_MESSAGE',
'CONNECT_WAIT_FOR_AGENT_MESSAGE_INTERVAL_IN_SECONDS',
'CONNECT_AGENT_JOINED_MESSAGE',
'CONNECT_AGENT_LEFT_MESSAGE',
'CONNECT_CHAT_ENDED_MESSAGE',
'CONNECT_ATTACH_CHAT_TRANSCRIPT',
'CONNECT_LIVE_CHAT_TERMS',
'CONNECT_START_LIVE_CHAT_LABEL',
'CONNECT_START_LIVE_CHAT_ICON',
'CONNECT_END_LIVE_CHAT_LABEL',
'CONNECT_END_LIVE_CHAT_ICON',
'CONNECT_TRANSCRIPT_MESSAGE_DELAY_IN_MSEC',
'APP_DOMAIN_NAME',
'UI_TOOLBAR_TITLE',
'UI_TOOLBAR_LOGO',
'BOT_AVATAR_IMG_URL',
'NEGATIVE_INTENT',
'POSITIVE_INTENT',
'HELP_INTENT',
'MIN_BUTTON_TOOLTIP_CONTENT',
'ENABLE_UPLOAD',
'UPLOAD_BUCKET_NAME'
].forEach(function (envVar) {
console.info('[INFO] Env var - %s: [%s]', envVar, process.env[envVar]);
});
/**
* Create an Mp3 file in the specified output folder for the given text, languageCode, and voiceId
* using AWS Polly.
* @param text
* @param languageCode
* @param voiceId
* @param output
*/
function createMp3(text, languageCode, voiceId, output) {
let lcDefinition = (languageCode.length > 0) ? `--language-code ${languageCode}` : '';
const cmd = `aws polly synthesize-speech --text "${text}" ${lcDefinition} --voice-id "${voiceId}" --output-format mp3 --text-type text "${output}"`
console.info(`createMp3 cmd is \n${cmd}`);
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.error(`createMp3 error: ${error.message}`);
}
if (stderr) {
console.error(`createMp3 stderr: ${stderr}`);
}
console.info(`createMp3 stdout: ${stdout}`);
});
}
/**
* Translate the specified text to the specified localeId and create an Mp3 in
* the specified output folder.
* @param localeId
* @param text
* @param output
*/
function translateAndCreateMp3(localeId, text, output) {
console.info(`translate '${text}' to ${localeId.trim()} with output of ${output}`);
lid = localeId.trim()
if (lid === 'en_US') {
return;
}
let targetPollyVoiceConfig = lexV2BotLocaleVoices[lid]
let enUSPollyVoiceConfig = lexV2BotLocaleVoices["en_US"];
console.info(`targetPollyVoiceConfig ${JSON.stringify(targetPollyVoiceConfig,null,4)}`);
if (targetPollyVoiceConfig) {
// translate the english text defined in CF template to the target language.
const targetTranslateLang = lid.split("_")[0];
const translateCmd = `aws translate translate-text --text "${text}" --source-language-code auto --target-language-code ${targetTranslateLang} --output json --query 'TranslatedText'`
console.info(`translate cmd is \n${translateCmd}`);
exec(translateCmd, (error, stdout, stderr) => {
if (error) {
console.error(`translate error: ${error.message}`);
}
if (stderr) {
console.error(`translate stderr: ${stderr}`);
}
console.info(`translate stdout: ${stdout.trim()}`);
// if a language code for the target locale exists, specify this for the polly command
createMp3(stdout.trim().replace(/['"]+/g, ''), targetPollyVoiceConfig.languageCode, targetPollyVoiceConfig.voiceId, output)
});
} else { // the specified locale can't be translated as it is not in the map. Generate an english version for this locale.
console.info(`Could not find specified locale "${lid}"`)
createMp3(text.trim().replace(/['"]+/g, ''), enUSPollyVoiceConfig.languageCode, enUSPollyVoiceConfig.voiceId, output)
}
}
Object.keys(config)
.map(function (confKey) { return config[confKey]; })
.forEach(function (item) {
fs.writeFile(item.file, JSON.stringify(item.conf, null, 2), function (err) {
if (err) {
console.error('[ERROR] could not write file: ', err);
process.exit(1);
}
// This following code pre-creates mp3 files needed for voice interaction. These files need to be pre-created
// and made available to the lex-web-ui for voice mode as the unauthenticated IAM role built for lex-web-ui no
// longer has access to Polly dynamically. The build IAM role does have access to Polly and Translate. The files
// are made available in the lex-web-ui web app bucket alongside of other UI assets. The files created are used
// for initial voice, the "All done" verbal response, and the "There was an error" verbal response.
console.info('[INFO] Updated file: ', item.file);
console.info('[INFO] Config contents: ', JSON.stringify(item.conf));
revisedConfig = item.conf;
let enUSPollyVoiceConfig = lexV2BotLocaleVoices["en_US"];
const {exec} = require("child_process");
const path = require('path');
const configDir = path.parse(item.file).dir;
console.info('[INFO] Config dir is: ', configDir);
// if an initial speach is set in the configuration, generate mp3 files for english and other configured locales
if (revisedConfig.lex && revisedConfig.lex.initialSpeechInstruction && revisedConfig.lex.initialSpeechInstruction.length > 0) {
// always generate an en_US mp3 if initial speech is defined
createMp3(revisedConfig.lex.initialSpeechInstruction.replace(/['"]+/g, ''), "en-US", enUSPollyVoiceConfig.voiceId,`${configDir}/initial_speech_en_US.mp3`);
// Iterate through the map of the configured v2BotLocaleIds and generate mp3 files with initial speech.
// This is only supported for LexV2 bots.
revisedConfig.lex.v2BotLocaleId.split(",").map((localeId) => {
lid = localeId.trim();
if (lid != "en_US") {
translateAndCreateMp3(lid, revisedConfig.lex.initialSpeechInstruction.replace(/['"]+/g, ''), `${configDir}/initial_speech_${lid}.mp3`)
}
});
}
// create mp3 audio files for other prompts used by lex-web-ui in english and other locales
if (revisedConfig && revisedConfig.lex) {
// Create special case MP3s that lexwebui might utilize
createMp3('All done', "en-US", enUSPollyVoiceConfig.voiceId, `${configDir}/all_done_en_US.mp3`);
createMp3('There was an error', "en-US", enUSPollyVoiceConfig.voiceId, `${configDir}/there_was_an_error_en_US.mp3`);
revisedConfig.lex.v2BotLocaleId.split(",").map((localeId) => {
let lid = localeId.trim();
translateAndCreateMp3(localeId, 'All done', `${configDir}/all_done_${lid}.mp3`)
translateAndCreateMp3(localeId, 'There was an error', `${configDir}/there_was_an_error_${lid}.mp3`)
});
}
});
});