From aff9dda8a32446c87ad90cf6107c82aac811af0f Mon Sep 17 00:00:00 2001 From: Alexander Teusz Date: Mon, 22 Feb 2021 17:59:46 +0100 Subject: [PATCH 1/5] initial commit for the webchat translate transformer --- endpoint/webchat/translate/README.md | 48 +++ .../docs/autoDetectLanguageExample.PNG | Bin 0 -> 56303 bytes .../docs/userDefinesLanguageExample.PNG | Bin 0 -> 9747 bytes endpoint/webchat/translate/transformer.ts | 360 ++++++++++++++++++ 4 files changed, 408 insertions(+) create mode 100644 endpoint/webchat/translate/README.md create mode 100644 endpoint/webchat/translate/docs/autoDetectLanguageExample.PNG create mode 100644 endpoint/webchat/translate/docs/userDefinesLanguageExample.PNG create mode 100644 endpoint/webchat/translate/transformer.ts diff --git a/endpoint/webchat/translate/README.md b/endpoint/webchat/translate/README.md new file mode 100644 index 0000000..2aaca0f --- /dev/null +++ b/endpoint/webchat/translate/README.md @@ -0,0 +1,48 @@ +# Realtime Translation Transformer + +For the Cognigy Webchat. + +With this Transformer function, Cognigy.AI is able to **translate messages** that were sent by the **user** and **virtual agent** automatically. In order to do so, one can select between the **Microsoft** or **Google Translator**. + +## Configuration + +- TRANSLATOR + - The Translation tool that should be used + - Options: + - 'google' + - 'microsoft' + +- TRANSLATOR_API_KEY + - The API Key of the selected Translation tool +- FLOW_LANGUAGE + - The language of the Cognigy.AI Flow that the user is talking to. This will be the locale, such as 'en', 'de', 'fr' a.s.o + - Options: + - [*Read more -> Google Translate*](https://cloud.google.com/translate/docs/languages) + - [*Read more -> Microsoft Translate*](https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support) +- AUTO_DETECT_LANGUAGE + - Whether the Transformer should detect the user's language or not + - Options + - true + - false + + +## Option 1: Auto Detect Language + +When this option is on (`true`), the selected Translation tool detects the language of the user's input message automatically and stores it in Cognigy.AI in order to answer in the same langauge as well. + +**Example:** + + + +## Option 2: User Defines Language + +If the user should be able to select a specific language, the `AUTO_DETECT_LANGUAGE` value should be off (`false`). In this case, the Cognigy.AI Flow needs to send the information about the preferred language by using a so-called DATA_ONLY message: + + + +Since the message doesn't contain a text, it is not displayed in the chat window. Thereforem, the transformer can use the value and store it internally in order to translate further messages into, in this case, *German* -- for example. + +### Supported Message Types + +- Text +- Text with Quick Replies \ No newline at end of file diff --git a/endpoint/webchat/translate/docs/autoDetectLanguageExample.PNG b/endpoint/webchat/translate/docs/autoDetectLanguageExample.PNG new file mode 100644 index 0000000000000000000000000000000000000000..4344f59e5720e3e5b75739b280269c00d5a302e3 GIT binary patch literal 56303 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

vuN%3N|}T#_bVnIFI12 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 Zmqp#LuqB8)xxhcB=Pk~ap1pqee*qo;>6HKg literal 0 HcmV?d00001 diff --git a/endpoint/webchat/translate/docs/userDefinesLanguageExample.PNG b/endpoint/webchat/translate/docs/userDefinesLanguageExample.PNG new file mode 100644 index 0000000000000000000000000000000000000000..7c9bf2fa618a45c43cf4175389cf6d3d01733ee0 GIT binary patch literal 9747 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 { + + try { + const googleOptions = { + method: 'POST', + uri: `https://translation.googleapis.com/language/translate/v2?key=${TRANSLATOR_API_KEY}`, + headers: { + 'Content-type': 'application/json' + }, + body: { + "q": textArray, + "target": language + }, + json: true + }; + + const response = await httpRequest(googleOptions); + + return response; + } catch (error) { + throw new Error(error.message); + } +} + +/** + * Microsoft Translate HTTP Request function + * @param {string[]} `textArray` A list of texts that should get translated + * @param {string} `language` The locale, such as de or en + */ +async function microsoftTranslate(textArray: string[], language: string): Promise { + + let microsoftTextArray: IMicrosoftTranslateRequestBody[] = []; + + // Fill the microsoftTextArray with a valid format of information + for (let text of textArray) { + microsoftTextArray.push({ + text + }); + } + + try { + const microsoftOptions = { + method: 'POST', + uri: `https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=${language}`, + headers: { + 'Ocp-Apim-Subscription-Key': TRANSLATOR_API_KEY, + 'Content-type': 'application/json', + 'Accept': 'application/json', + 'X-ClientTraceId': uuid.v4().toString() + }, + body: microsoftTextArray, + json: true + }; + + const response = await httpRequest(microsoftOptions); + + return response; + } catch (error) { + throw new Error(error.message); + } +} + +/** + * Translate the Cognigy.AI Webchat message into the selected language + * @param {any} `data` The Cognigy.AI data template message, such as Text, Text with Quick Replies, List or Gallery + * @param {string} `language` The locale to translate to, such as de or en + */ +async function translateCognigyMessage(data: any, language: string) { + + let translation: (IGoogleTranslateResponse | IMicrosoftTranslateResponse[]); + let textArray: string[] = []; + + // Check if type is text + if (data.text) { + // Check the selected translator + switch (TRANSLATOR) { + case 'google': + translation = await googleTranslate([data.text], language); + data.text = translation.data.translations[0].translatedText; + break; + case 'microsoft': + translation = await microsoftTranslate([data.text], language); + data.text = translation[0].translations[0].text; + break; + } + } + + // Check for Webchat Quick Replies + if (data?.data?._cognigy?._webchat?.message?.quick_replies) { + + // Translate the text of the quick reply text + textArray.push(data.data._cognigy._webchat.message.text); + + // Loop through the quick replies + for (let quickReply of data.data._cognigy._webchat?.message?.quick_replies) { + // Get the index of the current sentence in the list of sentences called 'text' + let index = data.data._cognigy._webchat?.message?.quick_replies.indexOf(quickReply); + textArray.push(data.data._cognigy._webchat?.message?.quick_replies[index].title); + } + + // Check the selected translator + switch (TRANSLATOR) { + case 'google': + translation = await googleTranslate(textArray, language); + + /** Translate message */ + data.data._cognigy._webchat.message.text = translation.data.translations[0].translatedText; + + for (let quickReply of data.data._cognigy._webchat?.message?.quick_replies) { + // Get the index of the current sentence in the list of sentences called 'text' + let index = data.data._cognigy._webchat?.message?.quick_replies.indexOf(quickReply); + data.data._cognigy._webchat.message.quick_replies[index].title = translation.data.translations[index + 1].translatedText + } + + break; + case 'microsoft': + translation = await microsoftTranslate(textArray, language); + + /** Translate message */ + data.data._cognigy._webchat.message.text = translation[0].translations[0].text; + + for (let quickReply of data.data._cognigy._webchat?.message?.quick_replies) { + // Get the index of the current sentence in the list of sentences called 'text' + let index = data.data._cognigy._webchat?.message?.quick_replies.indexOf(quickReply); + data.data._cognigy._webchat.message.quick_replies[index].title = translation[0].translations[index + 1].text + } + + break; + } + } + + // Check for Webchat Buttons + if (data.data?._cognigy?._webchat?.message?.attachment?.payload?.template_type === 'button') { + + // Translate the text of the quick reply text + textArray.push(data.data._cognigy._webchat.message.attachment.payload.text); + + // Loop through the quick replies + for (let button of data.data._cognigy._webchat?.message?.attachment.payload.buttons) { + // Get the index of the current sentence in the list of sentences called 'text' + let index = data.data._cognigy._webchat?.message?.attachment.payload.buttons.indexOf(button); + textArray.push(data.data._cognigy._webchat?.message?.attachment.payload.buttons[index].title); + } + + translation = await googleTranslate(textArray, language); + + data.data._cognigy._webchat.message.attachment.payload.text = translation.data.translations[0].translatedText; + + for (let button of data.data._cognigy._webchat?.message?.attachment.payload.buttons) { + // Get the index of the current sentence in the list of sentences called 'text' + let index = data.data._cognigy._webchat?.message?.attachment.payload.buttons.indexOf(button); + data.data._cognigy._webchat.message.attachment.payload.buttons[index].title = translation.data.translations[index + 1].translatedText + } + } + + // Check if type is list + if (data?.data?._cognigy?._webchat?.message?.attachment?.payload?.template_type === 'list') { + + // Loop through the list buttons + for (let element of data.data._cognigy._webchat?.message?.attachment.payload.elements) { + let index = data.data._cognigy._webchat?.message?.attachment.payload.elements.indexOf(element); + textArray.push(data.data._cognigy._webchat?.message?.attachment.payload.elements[index].title); + textArray.push(data.data._cognigy._webchat?.message?.attachment.payload.elements[index].subtitle); + } + + translation = await googleTranslate(textArray, language); + + for (let element of data.data._cognigy._webchat?.message?.attachment.payload.elements) { + // Get the index of the current sentence in the list of sentences called 'text' + let index = data.data._cognigy._webchat?.message?.attachment.payload.elements.indexOf(element); + data.data._cognigy._webchat.message.attachment.payload.elements[index].title = translation.data.translations[index].translatedText + data.data._cognigy._webchat.message.attachment.payload.elements[index].subtitle = translation.data.translations[index + 1].translatedText + } + } + return data; +} + + +/** + * Get the Google Translate Locale from plain text language + * @param {string} `language` The language string such as English or German + */ +function getLocale(language: string) { + + switch (language) { + case "German": + return 'de'; + case "French": + return 'fr'; + case "English": + return 'en'; + default: + return 'en'; + } +} + + +createSocketTransformer({ + + handleInput: async ({ payload, endpoint }) => { + + // Now the language could be used in order to tanslate the user's text, for example + let translation: (IGoogleTranslateResponse | IMicrosoftTranslateResponse[]); + let detectedSourceLanguage: string; + let sessionStorage = await getSessionStorage(payload.userId, payload.sessionId); + + switch (TRANSLATOR) { + case 'google': + translation = await googleTranslate([payload.text], FLOW_LANGUAGE); + + // Write detected language into the session storage + if (AUTO_DETECT_LANGUAGE) { + detectedSourceLanguage = translation.data.translations[0].detectedSourceLanguage; + sessionStorage.detectedSourceLanguage = detectedSourceLanguage; + } + + return { + userId: payload.userId, + sessionId: payload.sessionId, + // @ts-ignore + text: translation.data.translations[0].translatedText, + data: payload.data + }; + case 'microsoft': + translation = await microsoftTranslate([payload.text], FLOW_LANGUAGE); + + if (AUTO_DETECT_LANGUAGE) { + // Write detected language into the session storage + detectedSourceLanguage = translation[0].detectedLanguage.language; + sessionStorage.detectedSourceLanguage = detectedSourceLanguage; + } + + return { + userId: payload.userId, + sessionId: payload.sessionId, + text: translation[0].translations[0].text, + data: payload.data + }; + default: + return { + userId: payload.userId, + sessionId: payload.sessionId, + text: payload.text, + data: payload.data + }; + } + }, + handleOutput: async ({ processedOutput, output, endpoint, userId, sessionId }) => { + + // Create Session Storage + const sessionStorage = await getSessionStorage(userId, sessionId); + + // Check if language information is provided + if (processedOutput?.data?.language) { + sessionStorage.language = processedOutput.data.language; + } + + if (AUTO_DETECT_LANGUAGE) { + const detectedSourceLanguage: string = sessionStorage?.detectedSourceLanguage; + + // Translate the outgoing message + const translatedProcessedOutput = await translateCognigyMessage(processedOutput, detectedSourceLanguage) + return translatedProcessedOutput; + + } else if (sessionStorage.language) { + // Get stored language + const language = sessionStorage?.language; + let locale = getLocale(language); + + // Translate the outgoing message + const translatedProcessedOutput = await translateCognigyMessage(processedOutput, locale) + return translatedProcessedOutput; + } + + return processedOutput; + }, + handleExecutionFinished: async ({ sessionId, userId, endpoint }) => { + }, + handleInject: async ({ request, response, endpoint }) => { + + const userId = ""; + const sessionId = ""; + const text = ""; + const data = {} + + return { + userId, + sessionId, + text, + data + }; + }, + handleNotify: async ({ request, response, endpoint }) => { + + const userId = ""; + const sessionId = ""; + const text = ""; + const data = {} + + return { + userId, + sessionId, + text, + data + }; + } +}); \ No newline at end of file From 15e08c89b1fca1d9626cfb8dc80802499f2753bb Mon Sep 17 00:00:00 2001 From: Alexander Teusz Date: Tue, 23 Feb 2021 08:26:51 +0100 Subject: [PATCH 2/5] refactoring --- endpoint/webchat/translate/README.md | 27 +++++---- endpoint/webchat/translate/transformer.ts | 71 ++++++++--------------- 2 files changed, 41 insertions(+), 57 deletions(-) diff --git a/endpoint/webchat/translate/README.md b/endpoint/webchat/translate/README.md index 2aaca0f..02e3eed 100644 --- a/endpoint/webchat/translate/README.md +++ b/endpoint/webchat/translate/README.md @@ -6,24 +6,24 @@ With this Transformer function, Cognigy.AI is able to **translate messages** tha ## Configuration -- TRANSLATOR +- `TRANSLATOR` - The Translation tool that should be used - Options: - 'google' - 'microsoft' -- TRANSLATOR_API_KEY +- `TRANSLATOR_API_KEY` - The API Key of the selected Translation tool -- FLOW_LANGUAGE +- `FLOW_LANGUAGE` - The language of the Cognigy.AI Flow that the user is talking to. This will be the locale, such as 'en', 'de', 'fr' a.s.o - Options: - [*Read more -> Google Translate*](https://cloud.google.com/translate/docs/languages) - [*Read more -> Microsoft Translate*](https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support) -- AUTO_DETECT_LANGUAGE +- `AUTO_DETECT_LANGUAGE` - Whether the Transformer should detect the user's language or not - Options - - true - - false + - `true` + - `false` ## Option 1: Auto Detect Language @@ -32,17 +32,22 @@ When this option is on (`true`), the selected Translation tool detects the langu **Example:** - + ## Option 2: User Defines Language If the user should be able to select a specific language, the `AUTO_DETECT_LANGUAGE` value should be off (`false`). In this case, the Cognigy.AI Flow needs to send the information about the preferred language by using a so-called DATA_ONLY message: - + -Since the message doesn't contain a text, it is not displayed in the chat window. Thereforem, the transformer can use the value and store it internally in order to translate further messages into, in this case, *German* -- for example. +Since the message doesn't contain a text, it is not displayed in the chat window. Thereforem, the transformer can use the value and store it internally in order to translate further messages into, in this case, *German* (de) -- for example. -### Supported Message Types +**Important!** + +**Please make sure that the sent `language` value fits the schema of the selected Translation tool. In order to read more about this, take a look into the linked pages in the `FLOW_LANGUAGE` configuration at the top.** + +## Supported Message Types - Text -- Text with Quick Replies \ No newline at end of file +- Text with Quick Replies +- Text with Buttons \ No newline at end of file diff --git a/endpoint/webchat/translate/transformer.ts b/endpoint/webchat/translate/transformer.ts index d7bd02b..e1b025f 100644 --- a/endpoint/webchat/translate/transformer.ts +++ b/endpoint/webchat/translate/transformer.ts @@ -162,7 +162,7 @@ async function translateCognigyMessage(data: any, language: string) { for (let quickReply of data.data._cognigy._webchat?.message?.quick_replies) { // Get the index of the current sentence in the list of sentences called 'text' let index = data.data._cognigy._webchat?.message?.quick_replies.indexOf(quickReply); - data.data._cognigy._webchat.message.quick_replies[index].title = translation.data.translations[index + 1].translatedText + data.data._cognigy._webchat.message.quick_replies[index].title = translation.data.translations[index + 1].translatedText; } break; @@ -175,7 +175,7 @@ async function translateCognigyMessage(data: any, language: string) { for (let quickReply of data.data._cognigy._webchat?.message?.quick_replies) { // Get the index of the current sentence in the list of sentences called 'text' let index = data.data._cognigy._webchat?.message?.quick_replies.indexOf(quickReply); - data.data._cognigy._webchat.message.quick_replies[index].title = translation[0].translations[index + 1].text + data.data._cognigy._webchat.message.quick_replies[index].title = translation[0].translations[index + 1].text; } break; @@ -195,59 +195,39 @@ async function translateCognigyMessage(data: any, language: string) { textArray.push(data.data._cognigy._webchat?.message?.attachment.payload.buttons[index].title); } - translation = await googleTranslate(textArray, language); + // Check the selected translator + switch (TRANSLATOR) { + case 'google': + translation = await googleTranslate(textArray, language); - data.data._cognigy._webchat.message.attachment.payload.text = translation.data.translations[0].translatedText; + /** Translate message */ + data.data._cognigy._webchat.message.attachment.payload.text = translation.data.translations[0].translatedText; - for (let button of data.data._cognigy._webchat?.message?.attachment.payload.buttons) { - // Get the index of the current sentence in the list of sentences called 'text' - let index = data.data._cognigy._webchat?.message?.attachment.payload.buttons.indexOf(button); - data.data._cognigy._webchat.message.attachment.payload.buttons[index].title = translation.data.translations[index + 1].translatedText - } - } + for (let button of data.data._cognigy._webchat?.message?.attachment.payload.buttons) { + // Get the index of the current sentence in the list of sentences called 'text' + let index = data.data._cognigy._webchat?.message?.attachment.payload.buttons.indexOf(button); + data.data._cognigy._webchat.message.attachment.payload.buttons[index].title = translation.data.translations[index + 1].translatedText; + } - // Check if type is list - if (data?.data?._cognigy?._webchat?.message?.attachment?.payload?.template_type === 'list') { + break; + case 'microsoft': + translation = await microsoftTranslate(textArray, language); - // Loop through the list buttons - for (let element of data.data._cognigy._webchat?.message?.attachment.payload.elements) { - let index = data.data._cognigy._webchat?.message?.attachment.payload.elements.indexOf(element); - textArray.push(data.data._cognigy._webchat?.message?.attachment.payload.elements[index].title); - textArray.push(data.data._cognigy._webchat?.message?.attachment.payload.elements[index].subtitle); - } + /** Translate message */ + data.data._cognigy._webchat.message.attachment.payload.text = translation[0].translations[0].text; - translation = await googleTranslate(textArray, language); + for (let button of data.data._cognigy._webchat?.message?.attachment.payload.buttons) { + let index = data.data._cognigy._webchat?.message?.attachment.payload.buttons.indexOf(button); + data.data._cognigy._webchat.message.attachment.payload.buttons[index].title = translation[index + 1].translations[0].text; + } - for (let element of data.data._cognigy._webchat?.message?.attachment.payload.elements) { - // Get the index of the current sentence in the list of sentences called 'text' - let index = data.data._cognigy._webchat?.message?.attachment.payload.elements.indexOf(element); - data.data._cognigy._webchat.message.attachment.payload.elements[index].title = translation.data.translations[index].translatedText - data.data._cognigy._webchat.message.attachment.payload.elements[index].subtitle = translation.data.translations[index + 1].translatedText + break; } } - return data; -} - -/** - * Get the Google Translate Locale from plain text language - * @param {string} `language` The language string such as English or German - */ -function getLocale(language: string) { - - switch (language) { - case "German": - return 'de'; - case "French": - return 'fr'; - case "English": - return 'en'; - default: - return 'en'; - } + return data; } - createSocketTransformer({ handleInput: async ({ payload, endpoint }) => { @@ -318,10 +298,9 @@ createSocketTransformer({ } else if (sessionStorage.language) { // Get stored language const language = sessionStorage?.language; - let locale = getLocale(language); // Translate the outgoing message - const translatedProcessedOutput = await translateCognigyMessage(processedOutput, locale) + const translatedProcessedOutput = await translateCognigyMessage(processedOutput, language) return translatedProcessedOutput; } From 05604eea004bf0ccdda2dbd432b9a72a81fb9a2d Mon Sep 17 00:00:00 2001 From: Alexander Teusz Date: Tue, 23 Feb 2021 08:29:32 +0100 Subject: [PATCH 3/5] added deprecated warning; --- endpoint/realtimeTranslationTransformer/README.MD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/endpoint/realtimeTranslationTransformer/README.MD b/endpoint/realtimeTranslationTransformer/README.MD index 7de6754..282171e 100644 --- a/endpoint/realtimeTranslationTransformer/README.MD +++ b/endpoint/realtimeTranslationTransformer/README.MD @@ -1,3 +1,5 @@ +**DEPRECATED ([-> New Version](../webchat/translate))** + # Description This Transformer example shows how to translate the inputs from the user as well as the outputs from the Flow in order to enable one Flow in one language to be used in other languages. From 58a59f60b604c06b9e3c4cab01828bd199af3578 Mon Sep 17 00:00:00 2001 From: Alexander Teusz Date: Tue, 23 Feb 2021 08:39:07 +0100 Subject: [PATCH 4/5] added icon --- endpoint/webchat/translate/icon.png | Bin 0 -> 2482 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 endpoint/webchat/translate/icon.png diff --git a/endpoint/webchat/translate/icon.png b/endpoint/webchat/translate/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f24ff188136dd0a3c5a254924b376eda0911d8 GIT binary patch literal 2482 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 wx>6`+*nC1q?86pF07*qoM6N<$f&dJgy#N3J literal 0 HcmV?d00001 From 05791e5b19680a0244f6f510cf416bde0c1b992f Mon Sep 17 00:00:00 2001 From: Alexander Teusz Date: Tue, 23 Feb 2021 08:42:01 +0100 Subject: [PATCH 5/5] added icon as svg --- endpoint/webchat/translate/docs/icon.svg | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 endpoint/webchat/translate/docs/icon.svg diff --git a/endpoint/webchat/translate/docs/icon.svg b/endpoint/webchat/translate/docs/icon.svg new file mode 100644 index 0000000..1b721ae --- /dev/null +++ b/endpoint/webchat/translate/docs/icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + +