In this blog, we will learn how to integrate Cloud Natural Language API in Android application.
Natural language processing (NLP) describes the interaction between human language and computers.
It’s a technology that many people use daily and has been around for years, but is often taken for granted.
While NLP has uncountable use cases and benefits, some of the cases where NLP can be used are :
- Language translation
- Data analysis
- Text analytics
- Search results
- Predictive text
Well still if you want to learn more about NLP, then you can start understanding it by reading from internet/books and there is a lot of material available.
Now let’s have a look at what exactly is “Cloud Natural Language API”?
Natural Language uses machine learning to reveal the structure and meaning of text. You can extract information about people, places, and events, and better understand social media sentiment and customer conversations. Natural Language enables you to analyze text and also integrate it with your document storage on Google Cloud Storage.
–> Google Cloud NLP Documentation
Now, let’s see how we can use this Powerful API and include it in our android application.
Before we begin:
You will need to create your Google Application Credentials in a JSON file format.
If you are new to using Google Cloud Platform, simply login with your Gmail account over here –> https://console.cloud.google.com.
- Create a new project.
- Enable the Google Natural Language API for that project.
- Create a service account.
- Download a private key as JSON.
After this, keep this Credential JSON file with you, we will be needing it very soon.
Approach:
The approach to complete this integration is quite simple and easy to understand.
- Firstly, save the Credential JSON file in your android project under the res directory in a folder named raw like shown in the screenshot below :
- Now, we will create AccessTokenLoader.java class that is an extension of AsyncTaskLoader.java class. this class will help us to extract the credentials from our JSON file and set it in the Cloud Natural Language API request that we will be making.
- After that, we will create a very simple page with an edit text, a button, and a text view.
- In onCreate method, we will simply prepare Cloud Natural Language API with the credentials and the request to be made.
- On Click of the button, we will simply call the Cloud Natural Language API to get the results.
- The obtained results will be simply displayed in the Text view.
Let’s quickly start with the code.
CODE :
Firstly, add the lines below in your module-level build.gradle file (Path to the file –> Project–>app–> build.gradle)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Dependencies for Google API Client Libraries api("com.google.http-client:google-http-client:1.31.0") { exclude module: 'httpclient' exclude module: 'jsr305' } api ("com.google.api-client:google-api-client-android:1.30.2"){ exclude module: 'httpclient' exclude module: 'jsr305' } api("com.google.apis:google-api-services-language:v1-rev477-1.25.0") { exclude module: 'httpclient' exclude module: 'jsr305' } |
AccessTokenLoader.java class –>
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 |
public class AccessTokenLoader extends AsyncTaskLoader<String> { private static final String TAG = "AccessTokenLoader"; private static final String PREFS = "AccessTokenLoader"; private static final String PREF_ACCESS_TOKEN = "access_token"; public AccessTokenLoader(Context context) { super(context); } @Override protected void onStartLoading() { forceLoad(); } @Override public String loadInBackground() { final SharedPreferences prefs = getContext().getSharedPreferences(PREFS, Context.MODE_PRIVATE); String currentToken = prefs.getString(PREF_ACCESS_TOKEN, null); // Check if the current token is still valid for a while if (currentToken != null) { final GoogleCredential credential = new GoogleCredential() .setAccessToken(currentToken) .createScoped(CloudNaturalLanguageScopes.all()); final Long seconds = credential.getExpiresInSeconds(); if (seconds != null && seconds > 3600) { return currentToken; } } // ***** WARNING ***** // In this sample, we load the credential from a JSON file stored in a raw resource folder // of this client app. You should never do this in your app. Instead, store the file in your // server and obtain an access token from there. // ******************* final InputStream stream = getContext().getResources().openRawResource(R.raw.credential); try { final GoogleCredential credential = GoogleCredential.fromStream(stream) .createScoped(CloudNaturalLanguageScopes.all()); credential.refreshToken(); final String accessToken = credential.getAccessToken(); prefs.edit().putString(PREF_ACCESS_TOKEN, accessToken).apply(); return accessToken; } catch (IOException e) { Log.e(TAG, "Failed to obtain access token.", e); } return null; } } |
main_activity.xml file –>
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 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <TextView android:id="@+id/label_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:text="@string/enter_the_text_to_analyze_below" /> <androidx.appcompat.widget.AppCompatEditText android:id="@+id/text_et" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="8dp" android:hint="@string/your_text_goes_here" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:onClick="startAnalysis" android:text="@string/start_analysis" /> <androidx.core.widget.NestedScrollView android:id="@+id/nsv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" tools:visibility="visible" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_margin="8dp" android:padding="4dp" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/result_will_be_displayed_below" android:layout_marginBottom="8dp" /> <TextView android:id="@+id/result_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/result" /> </LinearLayout> </androidx.core.widget.NestedScrollView> </LinearLayout> |
MainActivity.java file –>
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 |
public class MainActivity extends AppCompatActivity { EditText editTextView; // View to get the text to be analyzed TextView resultTextView; // View to display the results obtained after analysis NestedScrollView nestedScrollView; // Wrapper view so that if the results are getting out of bounds from screen so the user can scroll and see complete results private static final int LOADER_ACCESS_TOKEN = 1; // Token used to initiate the request loader private GoogleCredential mCredential = null; //GoogleCredential object so that the requests for NLP Api could be made // A Thread on which the Api request will be made and results will be delivered. As network calls cannot be made on the amin thread, so we are creating a separate thread for the network calls private Thread mThread; // Google Request for the NLP Api. This actually is acting like a Http client queue that will process each request and response from the Google Cloud server private final BlockingQueue<CloudNaturalLanguageRequest<? extends GenericJson>> mRequests = new ArrayBlockingQueue<>(3); // Api for CloudNaturalLanguage from the Google Client library, this is the instance of our request that we will make to analyze the text. private CloudNaturalLanguage mApi = new CloudNaturalLanguage.Builder( new NetHttpTransport(), JacksonFactory.getDefaultInstance(), new HttpRequestInitializer() { @Override public void initialize(HttpRequest request) throws IOException { mCredential.initialize(request); } }).build(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editTextView = (EditText) findViewById(R.id.text_et); resultTextView = (TextView) findViewById(R.id.result_tv); nestedScrollView = (NestedScrollView) findViewById(R.id.nsv); prepareApi(); } /** * Method called on the click of the Button * @param view -> the view which is clicked */ public void startAnalysis(View view) { String textToAnalyze = editTextView.getText().toString(); if (TextUtils.isEmpty(textToAnalyze)) { editTextView.setError(getString(R.string.empty_text_error_msg)); } else { editTextView.setError(null); analyzeTextUsingCloudNLPApi(textToAnalyze); } } /** * This function will send the text to Cloud Api for analysis * @param text -> String to be analyzed */ public void analyzeTextUsingCloudNLPApi(String text) { try { mRequests.add(mApi .documents() .annotateText(new AnnotateTextRequest() .setDocument(new Document() .setContent(text) .setType("PLAIN_TEXT")) .setFeatures(new Features() .setExtractSyntax(true) .setExtractEntities(true) ))); } catch (IOException e) { Log.e("TAG", "Failed to create analyze request.", e); } } /** * Preparing the Cloud Api before maiking the actual request. * This method will actually initiate the AccessTokenLoader async task on completion * of which we will recieve the token that should be set in our request for Cloud NLP Api. */ private void prepareApi() { // Initiate token refresh getSupportLoaderManager().initLoader(LOADER_ACCESS_TOKEN, null, new LoaderManager.LoaderCallbacks<String>() { @Override public Loader<String> onCreateLoader(int id, Bundle args) { return new AccessTokenLoader(MainActivity.this); } @Override public void onLoadFinished(Loader<String> loader, String token) { setAccessToken(token); } @Override public void onLoaderReset(Loader<String> loader) { } }); } /** * This method will set the token from the Credentials.json file to the Google credential object. * @param token -> token recieved from the Credentials.json file. */ public void setAccessToken(String token) { mCredential = new GoogleCredential() .setAccessToken(token) .createScoped(CloudNaturalLanguageScopes.all()); startWorkerThread(); } /** * This method will actually initiate a Thread and on this thread we will execute our Api request * and responses. * * Responses recieved will be delivered from here. */ private void startWorkerThread() { if (mThread != null) { return; } mThread = new Thread(new Runnable() { @Override public void run() { while (true) { if (mThread == null) { break; } try { // API calls are executed here in this worker thread deliverResponse(mRequests.take().execute()); } catch (InterruptedException e) { Log.e("TAG", "Interrupted.", e); break; } catch (IOException e) { Log.e("TAG", "Failed to execute a request.", e); } } } }); mThread.start(); } /** * this method will handle the response recieved from the Cloud NLP request. * The response is a JSON object only. * This has been casted to GenericJson from Google Cloud so that the developers can easily parse through the same and can understand the response. * * * @param response --> the JSON object recieved as a response for the cloud NLP Api request */ private void deliverResponse(final GenericJson response) { Log.d("TAG", "Generic Response --> " + response); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(MainActivity.this, "Response Recieved from Cloud NLP API", Toast.LENGTH_SHORT).show(); try { resultTextView.setText(response.toPrettyString()); nestedScrollView.setVisibility(View.VISIBLE); } catch (IOException e) { e.printStackTrace(); } } }); } } |
We have successfully integrated the Cloud Natural Language API in our Android application.
Hope this article helps you.
Keep coding and Keep Sharing
For any queries, please feel free to add a comment in the comments section.
References –>
- https://cloud.google.com/natural-language/docs/quickstart-client-libraries
- https://cloud.google.com/natural-language/docs/apis
- https://github.com/GoogleCloudPlatform/android-docs-samples/tree/master/nl/Language