Text proofreading guide for Android

The MediaPipe Text Proofreader task lets you identify spelling, grammatical, and stylistic errors in a text and generate a corrected version while maintaining the original meaning. These instructions show you how to use the Text Proofreader in an Android app.

For more information about the capabilities, models, and configuration options of this task, see the Overview.

Code example

The Text Proofreader Android example app demonstrates the API on a physical Android device or emulator.

You can use the app as a starting point for your own Android app, or refer to it when modifying an existing app. The Text Proofreader example code is hosted on GitHub.

Setup

This section describes key steps for setting up your development environment and code projects specifically to use Text Proofreader. For general information on setting up your development environment for using MediaPipe tasks, including platform version requirements, see the Setup guide for Android.

Dependencies

Text Proofreader uses the com.google.mediapipe:tasks-text libraries. Add this dependency to the build.gradle file of your Android app development project. You can import the required dependencies with the following code:

dependencies {
    implementation 'com.google.mediapipe:tasks-text:latest.release'
}

Model

The MediaPipe Text Proofreader task requires a trained model that is compatible with this task. For more information on available trained models for Text Proofreader, see the task overview Models section.

Select and download the model, and then store it within your project directory:

<dev-project-root>/src/main/assets

Specify the path of the model within the options object. Use the setModelPath() function to specify the path used by the model. This method is referred to in the code example in the next section.

Create the task

You can use the createFromOptions() function to create the task. The createFromOptions() function accepts configuration options to set the proofreader options. For more information on configuration options, see Configuration options.

The following code demonstrates how to build and configure this task.

// Configure the options
TextProofreaderOptions options = TextProofreaderOptions.builder()
    .setModelPath("path/to/proofreader/model")
    .build();

// Create the task from options
// Note: 'context' is the Android Context
TextProofreader proofreader = TextProofreader.createFromOptions(context, options);

Configuration options

This task has the following configuration options for Android apps:

Option Name Description Value Range / Type Default Value
setModelAssetFileDescriptor File descriptor which contains the cached model file (at least one of these options must be provided). ParcelFileDescriptor -1
setModelPath The absolute local path to the proofreader model (at least one of these options must be provided). String ""
setMaxNumTokens Optional limit on the maximum context length (in tokens). If larger than the model's built-in capacity, the model's limit takes precedence. Integer Model default (8k)

Prepare data

Text Proofreader works with text (String) data. The task handles the data input preprocessing, including tokenization and tensor preprocessing. You do not need to perform any additional preprocessing of the input text beforehand.

String inputText = "Some input text for the proofreading task";

Run the task

To run the proofreading inference on the input text, you can use the synchronous approach which blocks the execution thread until the corrected text is returned, or the streaming approach which returns immediately and streams the results content through a callback interface.

Option A: Synchronous Proofreading

Use the synchronous approach when you want to wait for the entire text to be corrected and returned at once.

import com.google.mediapipe.tasks.text.textproofreader.TextProofreaderResult;

String textToProofread = "Here is a long block of text with typos...";

// Run proofreader (blocks current thread until done)
TextProofreaderResult result = proofreader.proofread(textToProofread);
String correctedText = result.getProofreadText();
System.out.println("Proofread text: " + correctedText);

Option B: Streaming Proofreading

The streaming approach is recommended for longer generation tasks or maintaining UI responsiveness. Here, a callback is provided to receive partial chunks of the proofread text as they are computed.

import com.google.mediapipe.tasks.text.textproofreader.TextProofreaderStreamingResult;

String textToProofread = "Here is a long block of text with typos...";

// Starts proofreading and returns immediately. Iteratively invokes callback.
proofreader.proofreadStreaming(textToProofread, new TextProofreader.ProofreaderResultCallback() {
     @Override
     public void onNext(TextProofreaderStreamingResult result) {
         // Appends the next stream chunk
         String chunk = result.getChunk();

         // e.g., runOnUiThread(() -> resultTextView.append(chunk));

         // Handle the corrections list when streaming is complete.
         if (result.isDone() && result.getCorrections() != null) {
             // Handle corrections list...
         }
     }

     @Override
     public void onError(Throwable throwable) {
         // Handle proofreading error
         System.err.println("Proofreading failed: " + throwable.getMessage());
     }

     @Override
     public void onDone() {
         // Fired when proofreading completes
         System.out.println("Proofreading finished!");
     }
});

Handle and display results

On executing inference:

  • For synchronous proofreading, it returns a TextProofreaderResult containing the final proofread text.
  • For streaming proofreading, it outputs TextProofreaderStreamingResult chunks repeatedly to the callback interface.
// TextProofreaderResult:
// Returns the entire proofread text
String fullProofreadText = result.getProofreadText();

// You can also get a list of corrections to highlight diffs in your UI
List<TextProofreaderResult.Correction> corrections = result.getCorrections();
for (TextProofreaderResult.Correction correction : corrections) {
   // Type is INSERTION, DELETION, or SAME
   TextProofreaderResult.CorrectionType type = correction.getType();
   String segment = correction.getText();
}

// TextProofreaderStreamingResult:
// Returns the newly generated proofread text chunk
String nextChunk = result.getChunk();
// Returns whether the stream iteration is complete
boolean isComplete = result.isDone();

Clean up

To free up memory and C++ resources, you must explicitly close the proofreader when done using it.

@Override
protected void onDestroy() {
    super.onDestroy();
    if (proofreader != null) {
        proofreader.close(); // Cleans up native handle
    }
}