From 39dfac36175d736992ae644ee97f3bd06e4c7f70 Mon Sep 17 00:00:00 2001 From: Gus Class Date: Wed, 19 Apr 2017 16:16:39 -0700 Subject: [PATCH 1/3] Adds example usage and tests for v1beta2 --- language/analysis/README.md | 7 + language/analysis/demo-beta.sh | 61 +++++++ .../cloud/language/samples/AnalyzeBeta.java | 169 ++++++++++++++++++ .../cloud/language/samples/AnalyzeBetaIT.java | 78 ++++++++ 4 files changed, 315 insertions(+) create mode 100755 language/analysis/demo-beta.sh create mode 100644 language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java create mode 100644 language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java diff --git a/language/analysis/README.md b/language/analysis/README.md index 14836f85f44..3d6c1f33ea5 100644 --- a/language/analysis/README.md +++ b/language/analysis/README.md @@ -68,6 +68,13 @@ java -cp target/language-entities-1.0-jar-with-dependencies.jar \ "The quick brown fox jumped over the lazy dog." ``` +Analyze sentiment Beta +``` +java -cp target/language-entities-1.0-jar-with-dependencies.jar \ + com.google.cloud.language.samples.AnalyzeBeta sentiment "Ich habe eine wundervolle Zeit." "DE" +``` + + Included with the sample are `demo.sh` and `demo.bat` which show additional examples of usage. diff --git a/language/analysis/demo-beta.sh b/language/analysis/demo-beta.sh new file mode 100755 index 00000000000..04ecf0af5f5 --- /dev/null +++ b/language/analysis/demo-beta.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Demonstrates how to run the AnalyzeBeta sample. + +########################################################################## +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################## + + +####################################### +# Performs a language operation on the given text or GCS object. +# Globals: +# None +# Arguments: +# $1 The operation to perform, either entities, sentiment, or syntax. +# $2 The text or GCS object to operate on. +# Returns: +# None +####################################### +function run_nl() { + local main_class=com.google.cloud.language.samples.AnalyzeBeta + local jar_file=target/language-entities-1.0-jar-with-dependencies.jar + java -cp ${jar_file} ${main_class} "$1" "$2" +} + +####################################### +# Exercises the sample code on various example text and GCS objects. +# Globals: +# None +# Arguments: +# None +# Returns: +# None +####################################### +function run_nl_all() { + local quote_de="Bananen sind die köstlichsten Früchte, ich liebe sie zu + essen. Ich mag sie so sehr wie Ananas." + local quote="Larry Page, Google's co-founder, once described the 'perfect + search engine' as something that 'understands exactly what you mean and + gives you back exactly what you want.' Since he spoke those words Google + has grown to offer products beyond search, but the spirit of what he said + remains." + local gs_path="gs:///file.txt" + + run_nl entities-sentiment "${quote}" + run_nl entities-sentiment "${gs_path}" + run_nl sentiment "${quote_de}" "DE" +} + +run_nl_all diff --git a/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java b/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java new file mode 100644 index 00000000000..6f0dd8fc047 --- /dev/null +++ b/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java @@ -0,0 +1,169 @@ +/* + * Copyright 2017 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.language.samples; + +import com.google.cloud.language.spi.v1beta2.LanguageServiceClient; + +import com.google.cloud.language.v1beta2.AnalyzeEntitySentimentRequest; +import com.google.cloud.language.v1beta2.AnalyzeEntitySentimentResponse; +import com.google.cloud.language.v1beta2.AnalyzeSentimentResponse; +import com.google.cloud.language.v1beta2.Document; +import com.google.cloud.language.v1beta2.Document.Type; +import com.google.cloud.language.v1beta2.EncodingType; +import com.google.cloud.language.v1beta2.Entity; +import com.google.cloud.language.v1beta2.EntityMention; +import com.google.cloud.language.v1beta2.Sentiment; +import com.google.cloud.language.v1beta2.Token; +import com.google.protobuf.Descriptors; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.GeneralSecurityException; +import java.util.List; +import java.util.Map; + +/** + * A sample application that uses the Natural Language API to perform + * entity, sentiment and syntax analysis. + */ +public class AnalyzeBeta { + private final LanguageServiceClient languageApi; + + /** + * Constructs a {@link Analyze} which connects to the Cloud Natural Language API. + */ + public AnalyzeBeta(LanguageServiceClient languageApi) { + this.languageApi = languageApi; + } + + + /** + * Detects entities,sentiment and syntax in a document using the Natural Language API. + */ + public static void main(String[] args) throws IOException, GeneralSecurityException { + if (args.length < 2 || args.length > 4) { + System.err.println("Usage:"); + System.err.printf( + "\tjava %s \"command\" \"text to analyze\" \"language\" \n", + Analyze.class.getCanonicalName()); + System.exit(1); + } + String command = args[0]; + String text = args[1]; + + AnalyzeBeta app = new AnalyzeBeta(LanguageServiceClient.create()); + + if (command.equals("entities-sentiment")) { + if (text.startsWith("gs://")) { + printEntities(System.out, app.entitySyntaxFile(text)); + } else { + printEntities(System.out, app.entitySyntaxText(text)); + } + } else if (command.equals("sentiment")) { + printSentiment(System.out, app.analyzeSentimentText(text, args[2])); + } + } + + /** + * Print the Sentiment {@code sentiment}. + */ + public static void printSentiment(PrintStream out, Sentiment sentiment) { + if (sentiment == null) { + out.println("No sentiment found"); + return; + } + out.println("Found sentiment."); + out.printf("\tMagnitude: %.3f\n", sentiment.getMagnitude()); + out.printf("\tScore: %.3f\n", sentiment.getScore()); + } + + /** + * Print a list of {@code entities}. + */ + public static void printEntities(PrintStream out, List entities) { + if (entities == null || entities.size() == 0) { + out.println("No entities found."); + return; + } + out.printf("Found %d entit%s.\n", entities.size(), entities.size() == 1 ? "y" : "ies"); + for (Entity entity : entities) { + out.printf("----\n\"%s\"\n", entity.getName()); + out.printf("\tSalience: %.3f\n", entity.getSalience()); + out.printf("\tSentiment Magnitude: %.3f\n", entity.getSentiment().getMagnitude()); + out.printf("\tSentiment Score: %.3f\n", entity.getSentiment().getScore()); + out.printf("\tType: %s\n", entity.getType()); + if (entity.getMetadataMap() != null) { + for (Map.Entry metadata : entity.getMetadataMap().entrySet()) { + out.printf("\tMetadata: %s = %s\n", metadata.getKey(), metadata.getValue()); + } + } + if (entity.getMentionsList() != null) { + for (EntityMention mention : entity.getMentionsList()) { + for (Map.Entry mentionSetMember : + mention.getAllFields().entrySet()) { + out.printf("\tMention: %s = %s\n", mentionSetMember.getKey(), + mentionSetMember.getValue()); + } + } + } + } + } + + /** + * Gets {@link Sentiment} from the string {@code text}. + */ + public Sentiment analyzeSentimentText(String text, String lang) throws IOException { + if (lang == null || lang.length() < 2) { + lang = "EN"; + } + + // Note: This does not work on App Engine standard. + Document doc = Document.newBuilder() + .setLanguage(lang) + .setContent(text).setType(Type.PLAIN_TEXT).build(); + AnalyzeSentimentResponse response = languageApi.analyzeSentiment(doc); + return response.getDocumentSentiment(); + } + + /** + * Gets {@link Entity}s from the string {@code text} with sentiment. + */ + public List entitySyntaxText(String text) throws IOException { + // Note: This does not work on App Engine standard. + Document doc = Document.newBuilder() + .setContent(text).setType(Type.PLAIN_TEXT).build(); + AnalyzeEntitySentimentRequest request = AnalyzeEntitySentimentRequest.newBuilder() + .setDocument(doc) + .setEncodingType(EncodingType.UTF16).build(); + AnalyzeEntitySentimentResponse response = languageApi.analyzeEntitySentiment(request); + return response.getEntitiesList(); + } + + /** + * Gets {@link Token}s from the contents of the object at the given GCS {@code path}. + */ + public List entitySyntaxFile(String path) throws IOException { + // Note: This does not work on App Engine standard. + Document doc = Document.newBuilder() + .setGcsContentUri(path).setType(Type.PLAIN_TEXT).build(); + AnalyzeEntitySentimentRequest request = AnalyzeEntitySentimentRequest.newBuilder() + .setDocument(doc) + .setEncodingType(EncodingType.UTF16).build(); + AnalyzeEntitySentimentResponse response = languageApi.analyzeEntitySentiment(request); + return response.getEntitiesList(); + } +} diff --git a/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java b/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java new file mode 100644 index 00000000000..c7ccc367263 --- /dev/null +++ b/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java @@ -0,0 +1,78 @@ +/* + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.language.samples; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.language.spi.v1beta2.LanguageServiceClient; +import com.google.cloud.language.v1beta2.Entity; +import com.google.cloud.language.v1beta2.Sentiment; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Integration (system) tests for {@link Analyze}. + */ +@RunWith(JUnit4.class) +@SuppressWarnings("checkstyle:abbreviationaswordinname") +public class AnalyzeBetaIT { + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private static final String BUCKET = PROJECT_ID; + + private AnalyzeBeta analyzeApp; + + @Before public void setup() throws Exception { + analyzeApp = new AnalyzeBeta(LanguageServiceClient.create()); + } + + @Test public void analyzeSentiment_returnPositiveGerman() throws Exception { + // Act + Sentiment sentiment = + analyzeApp.analyzeSentimentText( + "Ich hatte die schönste Erfahrung mit euch allen.", "DE"); + + // Assert + assertThat((double)sentiment.getMagnitude()).isGreaterThan(0.0); + assertThat((double)sentiment.getScore()).isGreaterThan(0.0); + } + + @Test public void analyzeSyntax_entitySyntaxText() throws Exception { + List entities = analyzeApp.entitySyntaxText("Oranges, grapes, and apples can be " + + "found in the cafeterias located in Mountain View, Seattle, and London."); + + List got = entities.stream().map(e -> e.getName()).collect(Collectors.toList()); + + // Assert + assertThat(got).named("entity names").contains("Seattle"); + } + + @Test public void analyzeSyntax_entitySyntaxFile() throws Exception { + List entities = + analyzeApp.entitySyntaxFile("gs://" + BUCKET + "/natural-language/gettysburg.txt"); + + List got = entities.stream().map(e -> e.getName()).collect(Collectors.toList()); + + // Assert + assertThat(got).named("entity names").contains("God"); + } +} From 6965e1171a77094a98a7705f62bb1120475baf3c Mon Sep 17 00:00:00 2001 From: Gus Class Date: Thu, 20 Apr 2017 10:15:14 -0700 Subject: [PATCH 2/3] License dates on new files, NPE fix, and renames on some methods. --- language/analysis/demo-beta.sh | 4 ++-- .../cloud/language/samples/AnalyzeBeta.java | 17 +++++++++++------ .../cloud/language/samples/AnalyzeBetaIT.java | 10 +++++----- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/language/analysis/demo-beta.sh b/language/analysis/demo-beta.sh index 04ecf0af5f5..e3e9625925c 100755 --- a/language/analysis/demo-beta.sh +++ b/language/analysis/demo-beta.sh @@ -3,7 +3,7 @@ # Demonstrates how to run the AnalyzeBeta sample. ########################################################################## -# Copyright 2016 Google Inc. All Rights Reserved. +# Copyright 2017 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -51,7 +51,7 @@ function run_nl_all() { gives you back exactly what you want.' Since he spoke those words Google has grown to offer products beyond search, but the spirit of what he said remains." - local gs_path="gs:///file.txt" + local gs_path="gs://cloud-samples-tests/natural-language/gettysburg.txt" run_nl entities-sentiment "${quote}" run_nl entities-sentiment "${gs_path}" diff --git a/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java b/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java index 6f0dd8fc047..74b592c2d5b 100644 --- a/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java +++ b/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java @@ -64,17 +64,21 @@ public static void main(String[] args) throws IOException, GeneralSecurityExcept } String command = args[0]; String text = args[1]; + String lang = null; + if (args.length > 2) { + lang = args[2]; + } AnalyzeBeta app = new AnalyzeBeta(LanguageServiceClient.create()); if (command.equals("entities-sentiment")) { if (text.startsWith("gs://")) { - printEntities(System.out, app.entitySyntaxFile(text)); + printEntities(System.out, app.entitySentimentFile(text)); } else { - printEntities(System.out, app.entitySyntaxText(text)); + printEntities(System.out, app.entitySentimentText(text)); } } else if (command.equals("sentiment")) { - printSentiment(System.out, app.analyzeSentimentText(text, args[2])); + printSentiment(System.out, app.analyzeSentimentText(text, lang)); } } @@ -142,7 +146,7 @@ public Sentiment analyzeSentimentText(String text, String lang) throws IOExcepti /** * Gets {@link Entity}s from the string {@code text} with sentiment. */ - public List entitySyntaxText(String text) throws IOException { + public List entitySentimentText(String text) throws IOException { // Note: This does not work on App Engine standard. Document doc = Document.newBuilder() .setContent(text).setType(Type.PLAIN_TEXT).build(); @@ -154,9 +158,10 @@ public List entitySyntaxText(String text) throws IOException { } /** - * Gets {@link Token}s from the contents of the object at the given GCS {@code path}. + * Gets {@link Entity}s from the contents of the object at the given GCS {@code path} + * with sentiment. */ - public List entitySyntaxFile(String path) throws IOException { + public List entitySentimentFile(String path) throws IOException { // Note: This does not work on App Engine standard. Document doc = Document.newBuilder() .setGcsContentUri(path).setType(Type.PLAIN_TEXT).build(); diff --git a/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java b/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java index c7ccc367263..80824a30db5 100644 --- a/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java +++ b/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Google Inc. All Rights Reserved. + * Copyright 2017 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,8 +56,8 @@ public class AnalyzeBetaIT { assertThat((double)sentiment.getScore()).isGreaterThan(0.0); } - @Test public void analyzeSyntax_entitySyntaxText() throws Exception { - List entities = analyzeApp.entitySyntaxText("Oranges, grapes, and apples can be " + + @Test public void analyzeSyntax_entitySentimentText() throws Exception { + List entities = analyzeApp.entitySentimentText("Oranges, grapes, and apples can be " + "found in the cafeterias located in Mountain View, Seattle, and London."); List got = entities.stream().map(e -> e.getName()).collect(Collectors.toList()); @@ -66,9 +66,9 @@ public class AnalyzeBetaIT { assertThat(got).named("entity names").contains("Seattle"); } - @Test public void analyzeSyntax_entitySyntaxFile() throws Exception { + @Test public void analyzeSyntax_entitySentimentFile() throws Exception { List entities = - analyzeApp.entitySyntaxFile("gs://" + BUCKET + "/natural-language/gettysburg.txt"); + analyzeApp.entitySentimentFile("gs://" + BUCKET + "/natural-language/gettysburg.txt"); List got = entities.stream().map(e -> e.getName()).collect(Collectors.toList()); From 97d778599a92e754d28ed00d778911e92dcfcf9c Mon Sep 17 00:00:00 2001 From: Gus Class Date: Thu, 20 Apr 2017 10:50:56 -0700 Subject: [PATCH 3/3] Updates copyright --- language/analysis/demo-beta.sh | 2 +- .../java/com/google/cloud/language/samples/AnalyzeBeta.java | 2 +- .../java/com/google/cloud/language/samples/AnalyzeBetaIT.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/language/analysis/demo-beta.sh b/language/analysis/demo-beta.sh index e3e9625925c..71d5116a142 100755 --- a/language/analysis/demo-beta.sh +++ b/language/analysis/demo-beta.sh @@ -3,7 +3,7 @@ # Demonstrates how to run the AnalyzeBeta sample. ########################################################################## -# Copyright 2017 Google Inc. All Rights Reserved. +# Copyright 2017 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java b/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java index 74b592c2d5b..f3d2714be60 100644 --- a/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java +++ b/language/analysis/src/main/java/com/google/cloud/language/samples/AnalyzeBeta.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Google Inc. All Rights Reserved. + * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java b/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java index 80824a30db5..183ca7aeae0 100644 --- a/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java +++ b/language/analysis/src/test/java/com/google/cloud/language/samples/AnalyzeBetaIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Google Inc. All Rights Reserved. + * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.