From 30a209e838db22b7960a0da4c1ae0be4305b3ab3 Mon Sep 17 00:00:00 2001 From: Ayush Goyal Date: Sat, 25 Mar 2023 22:12:55 +0530 Subject: [PATCH 1/3] feat: added translateText function for java --- java/translate_text/deps.gradle | 7 + java/translate_text/index.java | 255 ++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 java/translate_text/deps.gradle create mode 100644 java/translate_text/index.java diff --git a/java/translate_text/deps.gradle b/java/translate_text/deps.gradle new file mode 100644 index 00000000..2dfc451f --- /dev/null +++ b/java/translate_text/deps.gradle @@ -0,0 +1,7 @@ +dependencies { + implementation platform('com.google.cloud:libraries-bom:25.4.0') + implementation platform('software.amazon.awssdk:bom:2.15.0') + implementation 'software.amazon.awssdk:translate' + implementation 'com.google.code.gson:gson:2.9.0' + implementation 'com.google.cloud:google-cloud-translate' +} \ No newline at end of file diff --git a/java/translate_text/index.java b/java/translate_text/index.java new file mode 100644 index 00000000..a55fa589 --- /dev/null +++ b/java/translate_text/index.java @@ -0,0 +1,255 @@ +package io.translate_text.java; + +import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.json.gson.GsonFactory; +import com.google.api.services.translate.Translate; +import com.google.api.services.translate.model.TranslationsListResponse; +import com.google.api.services.translate.model.TranslationsResource; +import com.google.gson.Gson; +import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.translate.TranslateClient; +import software.amazon.awssdk.services.translate.model.TranslateException; +import software.amazon.awssdk.services.translate.model.TranslateTextRequest; +import software.amazon.awssdk.services.translate.model.TranslateTextResponse; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.util.*; + +final Gson gson = new Gson(); + +public RuntimeResponse main(RuntimeRequest req, RuntimeResponse res) { + // Validate that values present in the request are not empty (payload, variables) + RuntimeResponse errorResponse = checkEmptyPayloadAndVariables(req, res); + if (errorResponse != null) { + return errorResponse; + } + + // Validate the requested payload + String payloadString = req.getPayload().toString(); + + errorResponse = validatePayload(payloadString, res); + if (errorResponse != null) { + return errorResponse; + } + + Map payload = gson.fromJson(payloadString, Map.class); + + // Get provider from payload + String provider = payload.get("provider").toString(); + String sourceLanguageCode = payload.get("from").toString(); + + // Name API key is not empty + String API_KEY = "API_KEY"; + + errorResponse = validateVariables(req, res, API_KEY, provider); + if (errorResponse != null) { + return errorResponse; + } + Map variables = gson.fromJson(payloadString, Map.class); + String apiKey = variables.get(API_KEY).toString(); + + String translatedText = ""; + Map responseData = new HashMap<>(); + + try { + translatedText = translateText(payload, apiKey); + } catch (Exception e) { + responseData.put("success", false); + responseData.put("message", "Something went wrong while translating the text, please check with the developers. Error: " + e.getMessage()); + return res.json(responseData); + } + responseData.put("success", true); + responseData.put("message", translatedText); + responseData.put("from",sourceLanguageCode); + + return res.json(responseData); +} + +public String translateText(Map payload, String apiKey) throws GeneralSecurityException, IOException { + String provider = payload.get("provider").toString(); + String sourceLanguageCode = payload.get("from").toString(); + String targetLanguageCode = payload.get("to").toString(); + String text = payload.get("text").toString(); + + if (Objects.equals(Provider.AWS.toString(), provider)) { + return translateTexteUsingAWS(text, sourceLanguageCode, targetLanguageCode, apiKey); + } else if (Objects.equals(Provider.GOOGLE.toString(), provider)) { + return translateTextUsingGCP(text, targetLanguageCode, apiKey); + } else if (Objects.equals(Provider.AZURE.toString(), provider)) { + return translateTexteUsingAzure(text, targetLanguageCode, apiKey); + } + + return null; +} + + +public String translateTextUsingGCP(String text, String targetLanguage, String apiKey) throws GeneralSecurityException, IOException { + Translate t = new Translate.Builder(GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(), null) + .setApplicationName("Interacto") + .build(); + + Translate.Translations.List list = t.new Translations().list( + Arrays.asList(text), targetLanguage); + TranslationsListResponse translateResponse = list.setKey(apiKey).execute(); + List translationsResourceList = translateResponse.getTranslations(); + return translationsResourceList.get(0).getTranslatedText(); +} + +public String translateTexteUsingAWS(String text, String sourceLanguageCode, String targetLanguageCode, String apiKey) { + + try { + Region region = Region.US_WEST_2; + TranslateClient translateClient = TranslateClient.builder() + .region(region) + .credentialsProvider(ProfileCredentialsProvider.create()) + .build(); + + TranslateTextRequest textRequest = TranslateTextRequest.builder() + .sourceLanguageCode(sourceLanguageCode) + .targetLanguageCode(targetLanguageCode) + .text(text) + .build(); + + TranslateTextResponse textResponse = translateClient.translateText(textRequest); + System.out.println(textResponse.translatedText()); + translateClient.close(); + return textResponse.translatedText(); + } catch (TranslateException e) { + System.err.println(e.getMessage()); + System.exit(1); + } + return text; +} + +public String translateTexteUsingAzure(String text, String targetLanguageCode, String apiKey) throws IOException { + String endpointUrl = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=" + targetLanguageCode; + String requestBody = "[{\n\t\"text\": " + text + "\n}]"; + URL url = new URL(endpointUrl); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("POST"); + con.setRequestProperty("Content-Type", "application/json"); + con.setRequestProperty("Ocp-Apim-Subscription-Key", apiKey); + con.setRequestProperty("Accept", "application/json"); + con.setDoOutput(true); + OutputStream os = con.getOutputStream(); + byte[] input = requestBody.getBytes("utf-8"); + os.write(input, 0, input.length); + StringBuilder response = new StringBuilder(); + BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8")); + String responseLine = null; + while ((responseLine = br.readLine()) != null) { + response.append(responseLine.trim()); + } + br.close(); + con.disconnect(); + return response.toString(); +} + +private RuntimeResponse validateVariables(RuntimeRequest req, RuntimeResponse res, String apiKey, String provider) { + Map variables = req.getVariables(); + + if (!Objects.equals(Provider.AWS.toString(), provider) && !variables.containsKey(apiKey) || variables.get(apiKey) == null || variables.get(apiKey).trim().isEmpty()) { + Map responseData = new HashMap<>(); + responseData.put("success", false); + responseData.put("message", "Please pass a non-empty API Key(s) {}" + apiKey + " for translateText"); + + return res.json(responseData); + } + + return null; +} + +private RuntimeResponse validatePayload(String payloadString, RuntimeResponse res) { + Map responseData = new HashMap<>(); + Map payload; + ; + try { + payload = gson.fromJson(payloadString, Map.class); + } catch (Exception e) { + responseData.put("success", false); + responseData.put("message", "The payload is invalid. Example of valid payload:{\"provider\":\"aws\",\"from\":\"cs\",\"to\":\"en\",\"text\":\"Ahoj svet.\"}"); + return res.json(responseData); + } + + if (!payload.containsKey("provider")) { + responseData.put("success", false); + responseData.put("message", "Please provide a valid provider"); + return res.json(responseData); + } + + + if (!payload.containsKey("from")) { + responseData.put("success", false); + responseData.put("message", "Please provide a valid from"); + return res.json(responseData); + } + + if (!payload.containsKey("to")) { + responseData.put("success", false); + responseData.put("message", "Please provide a valid to"); + return res.json(responseData); + } + + if (!payload.containsKey("text")) { + responseData.put("success", false); + responseData.put("message", "Please provide a valid text"); + return res.json(responseData); + } + + String provider = payload.get("provider").toString(); + String from = payload.get("from").toString(); + String to = payload.get("to").toString(); + String text = payload.get("text").toString(); + + if (provider == null || provider.isEmpty()) { + responseData.put("success", false); + responseData.put("message", "Provided provider: " + provider + " is not valid, please provide a valid provider"); + return res.json(responseData); + } + + if (from == null || from.isEmpty()) { + responseData.put("success", false); + responseData.put("message", "Provided from: " + from + " is not valid, please provide a valid from value"); + return res.json(responseData); + } + + if (to == null || to.isEmpty()) { + responseData.put("success", false); + responseData.put("message", "Provided to: " + to + " is not valid, please provide a valid to value"); + return res.json(responseData); + } + + if (text == null || text.isEmpty()) { + responseData.put("success", false); + responseData.put("message", "Provided text: " + text + " is not valid, please provide a valid text value"); + return res.json(responseData); + } + + return null; +} + +private RuntimeResponse checkEmptyPayloadAndVariables(RuntimeRequest req, RuntimeResponse res) { + + Map responseData = new HashMap<>(); + + if (req.getPayload() == null || req.getPayload().trim().isEmpty() || req.getPayload().trim().equals("{}")) { + responseData.put("success", false); + responseData.put("message", "Payload is empty, expected a payload with bucketId"); + return res.json(responseData); + + } + if (req.getVariables() == null) { + responseData.put("success", false); + responseData.put("message", "Empty function variables found. You need to pass an API key."); + return res.json(responseData); + } + + return null; +} \ No newline at end of file From 483439cf3a7b9074dd930565d901b063a6191f12 Mon Sep 17 00:00:00 2001 From: Ayush Goyal Date: Sun, 2 Apr 2023 01:52:23 +0530 Subject: [PATCH 2/3] 4147 - Write a translateText() Function using Java --- java/translate_text/deps.gradle | 1 + java/translate_text/index.java | 104 +++++++++++++++++++------------- 2 files changed, 63 insertions(+), 42 deletions(-) diff --git a/java/translate_text/deps.gradle b/java/translate_text/deps.gradle index 2dfc451f..7d8f6730 100644 --- a/java/translate_text/deps.gradle +++ b/java/translate_text/deps.gradle @@ -4,4 +4,5 @@ dependencies { implementation 'software.amazon.awssdk:translate' implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.cloud:google-cloud-translate' + implementation 'com.squareup.okhttp3:okhttp:3.2.0' } \ No newline at end of file diff --git a/java/translate_text/index.java b/java/translate_text/index.java index a55fa589..b7c434c3 100644 --- a/java/translate_text/index.java +++ b/java/translate_text/index.java @@ -12,6 +12,9 @@ import software.amazon.awssdk.services.translate.model.TranslateException; import software.amazon.awssdk.services.translate.model.TranslateTextRequest; import software.amazon.awssdk.services.translate.model.TranslateTextResponse; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import okhttp3.*; import java.io.BufferedReader; import java.io.IOException; @@ -24,7 +27,7 @@ final Gson gson = new Gson(); -public RuntimeResponse main(RuntimeRequest req, RuntimeResponse res) { +public RuntimeResponse main(RuntimeRequest req, RuntimeResponse res) throws Exception { // Validate that values present in the request are not empty (payload, variables) RuntimeResponse errorResponse = checkEmptyPayloadAndVariables(req, res); if (errorResponse != null) { @@ -45,21 +48,23 @@ public RuntimeResponse main(RuntimeRequest req, RuntimeResponse res) { String provider = payload.get("provider").toString(); String sourceLanguageCode = payload.get("from").toString(); - // Name API key is not empty String API_KEY = "API_KEY"; + String REGION = "REGION"; + String SECRET_ACCESS_KEY = "SECRET_ACCESS_KEY"; - errorResponse = validateVariables(req, res, API_KEY, provider); + errorResponse = validateVariables(req, res, API_KEY, SECRET_ACCESS_KEY, REGION, provider); if (errorResponse != null) { return errorResponse; } - Map variables = gson.fromJson(payloadString, Map.class); - String apiKey = variables.get(API_KEY).toString(); + + Map variables = req.getVariables(); + String apiKey = variables.get(API_KEY); String translatedText = ""; Map responseData = new HashMap<>(); try { - translatedText = translateText(payload, apiKey); + translatedText = translateText(payload, variables, apiKey); } catch (Exception e) { responseData.put("success", false); responseData.put("message", "Something went wrong while translating the text, please check with the developers. Error: " + e.getMessage()); @@ -67,23 +72,25 @@ public RuntimeResponse main(RuntimeRequest req, RuntimeResponse res) { } responseData.put("success", true); responseData.put("message", translatedText); - responseData.put("from",sourceLanguageCode); + responseData.put("from", sourceLanguageCode); return res.json(responseData); } -public String translateText(Map payload, String apiKey) throws GeneralSecurityException, IOException { +public String translateText(Map payload, Map variables, String apiKey) throws GeneralSecurityException, IOException { String provider = payload.get("provider").toString(); String sourceLanguageCode = payload.get("from").toString(); String targetLanguageCode = payload.get("to").toString(); String text = payload.get("text").toString(); - if (Objects.equals(Provider.AWS.toString(), provider)) { - return translateTexteUsingAWS(text, sourceLanguageCode, targetLanguageCode, apiKey); - } else if (Objects.equals(Provider.GOOGLE.toString(), provider)) { + if (Objects.equals("aws", provider)) { + String secretAccessKey = variables.get("SECRET_ACCESS_KEY"); + return translateTexteUsingAWS(text, sourceLanguageCode, targetLanguageCode, apiKey, secretAccessKey); + } else if (Objects.equals("google", provider)) { return translateTextUsingGCP(text, targetLanguageCode, apiKey); - } else if (Objects.equals(Provider.AZURE.toString(), provider)) { - return translateTexteUsingAzure(text, targetLanguageCode, apiKey); + } else if (Objects.equals("azure", provider)) { + String region = variables.get("REGION"); + return translateTexteUsingAzure(text, sourceLanguageCode, targetLanguageCode, apiKey, region); } return null; @@ -102,13 +109,13 @@ public String translateTextUsingGCP(String text, String targetLanguage, String a return translationsResourceList.get(0).getTranslatedText(); } -public String translateTexteUsingAWS(String text, String sourceLanguageCode, String targetLanguageCode, String apiKey) { +public String translateTexteUsingAWS(String text, String sourceLanguageCode, String targetLanguageCode, String accessKeyId, String secretAccessKey) { try { Region region = Region.US_WEST_2; TranslateClient translateClient = TranslateClient.builder() .region(region) - .credentialsProvider(ProfileCredentialsProvider.create()) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKeyId, secretAccessKey))) .build(); TranslateTextRequest textRequest = TranslateTextRequest.builder() @@ -128,38 +135,51 @@ public String translateTexteUsingAWS(String text, String sourceLanguageCode, Str return text; } -public String translateTexteUsingAzure(String text, String targetLanguageCode, String apiKey) throws IOException { - String endpointUrl = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=" + targetLanguageCode; - String requestBody = "[{\n\t\"text\": " + text + "\n}]"; - URL url = new URL(endpointUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("POST"); - con.setRequestProperty("Content-Type", "application/json"); - con.setRequestProperty("Ocp-Apim-Subscription-Key", apiKey); - con.setRequestProperty("Accept", "application/json"); - con.setDoOutput(true); - OutputStream os = con.getOutputStream(); - byte[] input = requestBody.getBytes("utf-8"); - os.write(input, 0, input.length); - StringBuilder response = new StringBuilder(); - BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8")); - String responseLine = null; - while ((responseLine = br.readLine()) != null) { - response.append(responseLine.trim()); - } - br.close(); - con.disconnect(); - return response.toString(); +public String translateTexteUsingAzure(String text, String sourceLanguageCode, String targetLanguageCode, String apiKey, String region) throws IOException { + String endpointUrl = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&from=" + sourceLanguageCode + "&to=" + targetLanguageCode; + String requestBody = "[{\"text\":\"" + text + "\"}]"; + + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = RequestBody.create(mediaType, + requestBody); + Request request = new Request.Builder() + .url(endpointUrl) + .post(body) + .addHeader("Ocp-Apim-Subscription-Key", apiKey) + // location required if you're using a multi-service or regional (not global) resource. + .addHeader("Ocp-Apim-Subscription-Region", region) + .addHeader("Content-type", "application/json") + .build(); + Response response = client.newCall(request).execute(); + String res = response.body().string(); + JsonParser parser = new JsonParser(); + JsonElement json = parser.parse(res); + String answer = json.getAsJsonArray().getAsJsonArray().get(0).getAsJsonObject().get("translations").getAsJsonArray().get(0).getAsJsonObject().get("text").getAsString(); + + return answer; } -private RuntimeResponse validateVariables(RuntimeRequest req, RuntimeResponse res, String apiKey, String provider) { +private RuntimeResponse validateVariables(RuntimeRequest req, RuntimeResponse res, String apiKey, String secretAccessKey, String region, String provider) { Map variables = req.getVariables(); - if (!Objects.equals(Provider.AWS.toString(), provider) && !variables.containsKey(apiKey) || variables.get(apiKey) == null || variables.get(apiKey).trim().isEmpty()) { + if (!variables.containsKey(apiKey) || variables.get(apiKey) == null || variables.get(apiKey).trim().isEmpty()) { Map responseData = new HashMap<>(); responseData.put("success", false); - responseData.put("message", "Please pass a non-empty API Key(s) {}" + apiKey + " for translateText"); + responseData.put("message", "Please pass a non-empty API Key(s) " + apiKey + " for translateText"); + return res.json(responseData); + } + if (Objects.equals("aws", provider) && (!variables.containsKey(secretAccessKey) || variables.get(secretAccessKey) == null || variables.get(secretAccessKey).trim().isEmpty())) { + Map responseData = new HashMap<>(); + responseData.put("success", false); + responseData.put("message", "Please pass a non-empty " + secretAccessKey + " for translateText"); + return res.json(responseData); + } + + if (Objects.equals("azure", provider) && (!variables.containsKey(region) || variables.get(region) == null || variables.get(region).trim().isEmpty())) { + Map responseData = new HashMap<>(); + responseData.put("success", false); + responseData.put("message", "Please pass a non-empty " + region + " for translateText"); return res.json(responseData); } @@ -241,13 +261,13 @@ private RuntimeResponse checkEmptyPayloadAndVariables(RuntimeRequest req, Runtim if (req.getPayload() == null || req.getPayload().trim().isEmpty() || req.getPayload().trim().equals("{}")) { responseData.put("success", false); - responseData.put("message", "Payload is empty, expected a payload with bucketId"); + responseData.put("message", "Payload is empty, expected a payload with {\"provider\":\"aws\",\"from\":\"cs\",\"to\":\"en\",\"text\":\"Ahoj svet.\"}"); return res.json(responseData); } if (req.getVariables() == null) { responseData.put("success", false); - responseData.put("message", "Empty function variables found. You need to pass an API key."); + responseData.put("message", "Empty function variables found. You need to pass an API_KEY"); return res.json(responseData); } From f153cce9cf0c5ada84680aa5faedcbb0d75aba31 Mon Sep 17 00:00:00 2001 From: Ayush Goyal Date: Sun, 2 Apr 2023 02:03:48 +0530 Subject: [PATCH 3/3] 4147 - Write a translateText() Function using Java added README --- java/translate_text/README.md | 75 +++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 java/translate_text/README.md diff --git a/java/translate_text/README.md b/java/translate_text/README.md new file mode 100644 index 00000000..e24bd61f --- /dev/null +++ b/java/translate_text/README.md @@ -0,0 +1,75 @@ +# 🌐 Translate text from one language to another + +A Java Cloud Function for translating text from one language to another. Includes support for [Google](https://translate.google.com/), [AWS](https://aws.amazon.com/translate/), and [Azure](https://azure.microsoft.com/en-us/products/cognitive-services/translator/) + +_Example input:_ + +```json +{ + "provider": "google", + "text": "Hello from Open Runtimes", + "from": "en", + "to": "es" +} +``` + +_Example output:_ + +```json +{ + "response": { + "message": "Hola desde Open Runtimes", + "success": true, + "from": "en" + }, + "stdout": "", + "stderr": "" +} +``` + +## 📝 Variables + +#### Translating with `google` + +No variables required + +- **API_KEY** - Access key for GCP + +#### Translate with `aws` + +- **AWS_ACCESS_KEY** - Access key for AWS +- **AWS_SECRET_KEY** - Secret Key for AWS + +#### Translating with `azure` + +- **TRANSLATOR_KEY** - Translator Key for Azure +- **REGION** - Region for Azure + +## 🚀 Deployment + +1. Clone this repository, and enter this function folder: + +```bash +git clone https://github.com/open-runtimes/examples.git && cd examples +cd java/translate_text +``` + +2. Build the code: + +```bash +docker run -e INTERNAL_RUNTIME_ENTRYPOINT=Index.java --rm --interactive --tty --volume $PWD:/usr/code openruntimes/java:v2-8.0 sh /usr/local/src/build.sh +``` + +3. Spin-up open-runtime: + +```bash +docker run -p 3000:3000 -e INTERNAL_RUNTIME_KEY=secret-key --rm --interactive --tty --volume $PWD/code.tar.gz:/tmp/code.tar.gz:ro openruntimes/java:v2-8.0 sh /usr/local/src/start.sh +``` + +Your function is now listening on port `3000`, and you can execute it by sending `POST` request with appropriate authorization headers. To learn more about runtime, you can visit Java runtime [README](https://github.com/open-runtimes/open-runtimes/tree/main/runtimes/java-8.0). + +## 📝 Notes + +- This function is designed for use with Appwrite Cloud Functions. You can learn more about it in [Appwrite docs](https://appwrite.io/docs/functions). +- This example is compatible with JAVA 8. Other versions may work but are not guarenteed to work as they haven't been tested. +- For aws as a provider, default region US_WEST_2 has been configured