GenAI Proofreading API

With ML Kit's GenAI Proofreading API, you can help users check their grammar and spelling on short pieces of text.

Key capabilities

  • Proofread text inputted through keyboard or voice
  • Requests will return at least one suggestion. If multiple suggestions are returned, results will be sorted by descending confidence.

Example results

Input

Input Type

Output

this is a short msg

Keyboard

This is a short message

The project is nearly compleete butt needs too be reviewed

Keyboard

The project is nearly complete but needs to be reviewed

Please meat me at the bear,

Voice

Please meet me at the bar.

Getting Started

To get started with the GenAI Proofreading API, add this dependency to your project's build file.

  implementation 
 ( 
 "com.google.mlkit:genai-proofreading:1.0.0-beta1" 
 ) 
 

Then, configure and obtain a Proofreader client with specific language and input type settings. Check and ensure the necessary on-device model features are available (triggering a download if needed). Submit the text you want to analyze in a ProofreadingRequest , execute the proofreading inference, and finally process the returned suggestions for correcting the text.

Kotlin

  val 
  
 textToProofread 
  
 = 
  
 "The praject is compleet but needs too be reviewd" 
 // Define task with required input and output format 
 val 
  
 options 
  
 = 
  
 ProofreaderOptions 
 . 
 builder 
 ( 
 context 
 ) 
  
 // InputType can be KEYBOARD or VOICE. VOICE indicates that 
  
 // the user generated text based on audio input. 
  
 . 
 setInputType 
 ( 
 ProofreaderOptions 
 . 
 InputType 
 . 
 KEYBOARD 
 ) 
  
 // Refer to ProofreaderOptions.Language for available 
  
 // languages 
  
 . 
 setLanguage 
 ( 
 ProofreaderOptions 
 . 
 Language 
 . 
 ENGLISH 
 ) 
  
 . 
 build 
 () 
 val 
  
 proofreader 
  
 = 
  
 Proofreading 
 . 
 getClient 
 ( 
 options 
 ) 
 suspend 
  
 fun 
  
 prepareAndStartProofread 
 () 
  
 { 
  
 // Check feature availability, status will be one of the 
  
 // following: UNAVAILABLE, DOWNLOADABLE, DOWNLOADING, AVAILABLE 
  
 val 
  
 featureStatus 
  
 = 
  
 proofreader 
 . 
 checkFeatureStatus 
 (). 
 await 
 () 
  
 if 
  
 ( 
 featureStatus 
  
 == 
  
 FeatureStatus 
 . 
 DOWNLOADABLE 
 ) 
  
 { 
  
 // Download feature if necessary. 
  
 // If downloadFeature is not called, the first inference 
  
 // request will also trigger the feature to be downloaded 
  
 // if it's not already downloaded. 
  
 proofreader 
 . 
 downloadFeature 
 ( 
 object 
  
 : 
  
 DownloadCallback 
  
 { 
  
 override 
  
 fun 
  
 onDownloadStarted 
 ( 
 bytesToDownload 
 : 
  
 Long 
 ) 
  
 { 
  
 } 
  
 override 
  
 fun 
  
 onDownloadFailed 
 ( 
 e 
 : 
  
 GenAiException 
 ) 
  
 { 
  
 } 
  
 override 
  
 fun 
  
 onDownloadProgress 
 ( 
  
 totalBytesDownloaded 
 : 
  
 Long 
  
 ) 
  
 {} 
  
 override 
  
 fun 
  
 onDownloadCompleted 
 () 
  
 { 
  
 startProofreadingRequest 
 ( 
 textToProofread 
 , 
  
 proofreader 
 ) 
  
 } 
  
 }) 
  
 } 
  
 else 
  
 if 
  
 ( 
 featureStatus 
  
 == 
  
 FeatureStatus 
 . 
 DOWNLOADING 
 ) 
  
 { 
  
 // Inference request will automatically run once feature is 
  
 // downloaded. 
  
 // If Gemini Nano is already downloaded on the device, the 
  
 // feature-specific LoRA adapter model will be downloaded 
  
 // very quickly. However, if Gemini Nano is not already 
  
 // downloaded, the download process may take longer. 
  
 startProofreadingRequest 
 ( 
 textToProofread 
 , 
  
 proofreader 
 ) 
  
 } 
  
 else 
  
 if 
  
 ( 
 featureStatus 
  
 == 
  
 FeatureStatus 
 . 
 AVAILABLE 
 ) 
  
 { 
  
 startProofreadingRequest 
 ( 
 textToProofread 
 , 
  
 proofreader 
 ) 
  
 } 
 } 
 suspend 
  
 fun 
  
 startProofreadingRequest 
 ( 
  
 text 
 : 
  
 String 
 , 
  
 proofreader 
 : 
  
 Proofreader 
 ) 
  
 { 
  
 // Create task request 
  
 val 
  
 proofreadingRequest 
  
 = 
  
 ProofreadingRequest 
 . 
 builder 
 ( 
 text 
 ). 
 build 
 () 
  
 // Start proofreading request with non-streaming response 
  
 // More than 1 result may be returned. If multiple suggestions 
  
 // are returned, results will be sorted by descending confidence. 
  
 val 
  
 proofreadingResults 
  
 = 
  
 proofreader 
 . 
 runInference 
 ( 
 proofreadingRequest 
 ). 
 await 
 (). 
 results 
  
 // You can also start a streaming request 
  
 // proofreader.runInference(proofreadingRequest) { newText - 
>  
 //     // show new text in UI 
  
 // } 
 } 
 // Be sure to release the resource when no longer needed 
 // For example, on viewModel.onCleared() or activity.onDestroy() 
 proofreader 
 . 
 close 
 () 
 

Java

  String 
  
 textToProofread 
  
 = 
  
 "The praject is compleet but needs too be reviewd" 
 ; 
 // Define task with required input and output format 
 ProofreaderOptions 
  
 proofreaderOptions 
  
 = 
  
  
 ProofreaderOptions 
  
 . 
 builder 
 ( 
 context 
 ) 
  
 // InputType can be KEYBOARD or VOICE. VOICE indicates that the 
  
 // user generated text based on audio input. 
  
 . 
 setInputType 
 ( 
 ProofreaderOptions 
 . 
 InputType 
 . 
 KEYBOARD 
 ) 
  
 // Refer to ProofreaderOptions.Language for available languages 
  
 . 
 setLanguage 
 ( 
 ProofreaderOptions 
 . 
 Language 
 . 
 ENGLISH 
 ) 
  
 . 
 build 
 (); 
 Proofreader 
  
 proofreader 
  
 = 
  
 Proofreading 
 . 
 getClient 
 ( 
 proofreaderOptions 
 ); 
 void 
  
 prepareAndStartProofread 
 ( 
 Context 
  
 context 
 ) 
  
 throws 
  
 ExecutionException 
 , 
  
 InterruptedException 
  
 { 
  
 // Check feature availability, status will be one of the following: 
  
 // UNAVAILABLE, DOWNLOADABLE, DOWNLOADING, AVAILABLE 
  
 try 
  
 { 
  
 int 
  
 featureStatus 
  
 = 
  
 proofreader 
 . 
 checkFeatureStatus 
 (). 
 get 
 (); 
  
 if 
  
 ( 
 featureStatus 
  
 == 
  
 FeatureStatus 
 . 
 DOWNLOADABLE 
 ) 
  
 { 
  
 // Download feature if necessary. 
  
 // If downloadFeature is not called, the first inference request 
  
 // will also trigger the feature to be downloaded if it's not 
  
 // already downloaded. 
  
 proofreader 
 . 
 downloadFeature 
 ( 
 new 
  
 DownloadCallback 
 () 
  
 { 
  
 @Override 
  
 public 
  
 void 
  
 onDownloadCompleted 
 () 
  
 { 
  
 startProofreadingRequest 
 ( 
 textToProofread 
 , 
  
 proofreader 
 ); 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 onDownloadFailed 
 ( 
 GenAiException 
  
 e 
 ) 
  
 { 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 onDownloadProgress 
 ( 
 long 
  
 totalBytesDownloaded 
 ) 
  
 { 
  
 } 
  
 @Override 
  
 public 
  
 void 
  
 onDownloadStarted 
 ( 
 long 
  
 bytesDownloaded 
 ) 
  
 { 
  
 } 
  
 }); 
  
 } 
  
 else 
  
 if 
  
 ( 
 featureStatus 
  
 == 
  
 FeatureStatus 
 . 
 DOWNLOADING 
 ) 
  
 { 
  
 // Inference request will automatically run once feature is 
  
 // downloaded. 
  
 // If Gemini Nano is already downloaded on the device, the 
  
 // feature-specific LoRA adapter model will be downloaded 
  
 // very quickly. However, if Gemini Nano is not already 
  
 // downloaded, the download process may take longer. 
  
 startProofreadingRequest 
 ( 
 textToProofread 
 , 
  
 proofreader 
 ); 
  
 } 
  
 else 
  
 if 
  
 ( 
 featureStatus 
  
 == 
  
 FeatureStatus 
 . 
 AVAILABLE 
 ) 
  
 { 
  
 startProofreadingRequest 
 ( 
 textToProofread 
 , 
  
 proofreader 
 ); 
  
 } 
  
 } 
  
 catch 
  
 ( 
 ExecutionException 
  
 | 
  
 InterruptedException 
  
 e 
 ) 
  
 { 
  
 e 
 . 
 printStackTrace 
 (); 
  
 } 
 } 
 void 
  
 startProofreadingRequest 
 ( 
 String 
  
 text 
 , 
  
 Proofreader 
  
 proofreader 
 ) 
  
 { 
  
 // Create task request 
  
 ProofreadingRequest 
  
 proofreadingRequest 
  
 = 
  
 ProofreadingRequest 
  
 . 
 builder 
 ( 
 text 
 ). 
 build 
 (); 
  
 try 
  
 { 
  
 // Start proofreading request with non-streaming response 
  
 // More than 1 result may be returned. If multiple suggestions are 
  
 // returned, results will be sorted by descending confidence. 
  
 proofreader 
 . 
 runInference 
 ( 
 proofreadingRequest 
 ). 
 get 
 (). 
 getResults 
 (); 
  
 // You can also start a streaming request 
  
 // proofreader.runInference(proofreadingRequest, newText -> { 
  
 //     // Show new text in UI 
  
 // }); 
  
 } 
  
 catch 
  
 ( 
 ExecutionException 
  
 | 
  
 InterruptedException 
  
 e 
 ) 
  
 { 
  
 e 
 . 
 printStackTrace 
 (); 
  
 } 
 } 
 // Be sure to release the resource when no longer needed 
 // For example, on viewModel.onCleared() or activity.onDestroy() 
 proofreader 
 . 
 close 
 (); 
 

How the model handles different input types

When the model has more information about how the user inputted text (keyboard or voice), it can better predict the type of errors that may be present. Keyboard-inputted text is more prone to misspelling with nearby keys, while voice-inputted text is more prone to misspelling of words with the same pronunciation.

Supported features and limitations

Proofreading is supported for the following languages: English, Japanese, French, German, Italian, Spanish, and Korean, and they are defined in ProofreaderOptions.Language . Input should be less than 256 tokens.

Availability of the specific feature configuration (specified by ProofreaderOptions ) may vary depending on the particular device's configuration and the models that have been downloaded to the device.

The most reliable way for developers to ensure that the intended API feature is supported on a device with the requested ProofreaderOptions is to call the checkFeatureStatus() method. This method provides the definitive status of feature availability on the device at runtime.

Common setup issues

ML Kit GenAI APIs rely on the Android AICore app to access Gemini Nano. When a device is just setup (including reset), or the AICore app is just reset (e.g. clear data, uninstalled then reinstalled), the AICore app may not have enough time to finish initialization (including downloading latest configurations from server). As a result, the ML Kit GenAI APIs may not function as expected. Here are the common setup error messages you may see and how to handle them:

Example error message How to handle
AICore failed with error type 4-CONNECTION_ERROR and error code 601-BINDING_FAILURE: AICore service failed to bind. This could happen when you install the app using ML Kit GenAI APIs immediately after device setup or when AICore is uninstalled after your app is installed. Updating AICore app then reinstalling your app should fix it.
AICore failed with error type 3-PREPARATION_ERROR and error code 606-FEATURE_NOT_FOUND: Feature ... is not available. This could happen when AICore hasn't finished downloading the latest configurations. When the device is connected to the internet, it usually takes a few minutes to a few hours to update. Restarting the device can speed up the update.

Note that if the device's bootloader is unlocked, you'll also see this error—this API does not support devices with unlocked bootloaders.
AICore failed with error type 1-DOWNLOAD_ERROR and error code 0-UNKNOWN: Feature ... failed with failure status 0 and error esz: UNAVAILABLE: Unable to resolve host ... Keep network connection, wait for a few minutes and retry.
Create a Mobile Website
View Site in Mobile | Classic
Share by: