Traducción de Google del lado del dispositivo con Jetpack Compose y MLKit | Via Suraj Sau | Diciembre de 2021

En este artículo, utilizaremos DigitalInk y On-device Translation de MLKit para implementar el recorrido del código de reconocimiento de caracteres (y traducción de texto) de Google Translate en Jetpack Compose.

Este es el código fuente de mi implementación.
Vamos a poner uno @Composable Canvas El usuario dibujará personajes en la pantalla.
Este es un caso de uso estándar en el que interceptamos eventos táctiles View Y traducirlo a Path Sobre el lienzo. Extiéndalo a Jetpack Compose,
- usar
Modifier.pointerInteropFiltertenemosMotionEventSimilar a enandroid.view.ViewToque el monitor. - Por conveniencia, creé
sealed class DrawEventEsto se asignará a la correspondienteMotionEvent. rememberestaPathObjeto, porque no cambia la reorganización.Establezca el valor enmutableStateOfEn la devolución de llamada, se desencadena una recombinación, en la que se crea una nueva subruta o se modifica la subruta actual.path.lineTo()También puede reemplazarpath.quadraticBezierTo()Utilizo la ruta cuadrática solo para suavizar las esquinas afiladas.- Finalmente, al final de cada llamada combinada
drawPath()
MLKit de Google proporciona Digital Ink, un paquete de software listo para usar para el reconocimiento de caracteres en más de 300 idiomas. También proporciona soporte para el reconocimiento de escritura a mano para servicios como Gboard y Google Translate.
Los principales componentes de los que trataremos principalmente son Ink.Stroke, DigitalInkRecognitionModel con DigitalInkRecognizer.
Inicialicémoslos mientras discutimos su propósito.
Ink.Stroke: Este objeto de datos contiene una lista de coordenadas (Ink.Point) Para dibujar la información de la forma, esta es nuestra entradaRecognitionModel.MotionEventLuego agregue las coordenadas obtenidas en la devolución de llamada a esto.
DigitalInkRecognitionModel: Este es el modelo ML correspondiente al idioma específico en el que se van a reconocer los personajes. El constructor utiliza «modelIndentifier» para especificar el idioma de reconocimiento de caracteres.Para este ejemplo, usaremos el modelo japonés, entonces pasamosDigitalInkRecognitionModelIdentifier.JADigitalInkRecognizer: Esto necesita ser generadoInk.StrokeComo entrada del modelo ML y salida, los resultados de los personajes predichos por el modelo.
Consultar la disponibilidad del modelo

Antes de usar Digital Ink, para admitir el reconocimiento de caracteres en un idioma específico, necesitamos descargar los datos del modelo ML de un idioma específico (aproximadamente 20 MB por idioma) y ponerlo a disposición localmente.
Puede consultar Digital Ink | Descarga del modelo de gestión para obtener información más detallada. Este es mi código de referencia.
Una vez que los modelos dibujables Canvas y MLKit estén listos, agreguemos devoluciones de llamada para manejar la construcción Ink.Stroke Y disparar Recognizer.recognize() despues de terminar.
Por conveniencia, agregué sealed class DrawEvent Mapeado al correspondiente MotionEvent.
Dentro de onDrawEvent llamar de vuelta,
MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE: Esto significa que el usuario está tocando el lienzo para dibujar.Agregaremos las coordenadas del evento obtenidas aInk.Stroke.BuilderMotionEvent.ACTION_UP: Indica que el usuario ha dejado de tocar el lienzo, indicando así el final del dibujo.Ahora podemos construir el generadoInk.StrokeY pasarlo aRecognizer.recognize().
existeonSuccessRecuperamos el resultado de la predicción (RecognitionResult.candidates) show.existeonCompleteFueron puestosInk.Stroke.BuilderEmpiece a obtener las coordenadas del siguiente carácter que se dibujará.
En este punto, el fragmento de código anterior funciona bien. Sin embargo, en el ejemplo siguiente, la predicción no es correcta en absoluto.
Aunque algunos caracteres se pueden escribir con un solo trazo, como i, t Y personajes complejos como 終, Incluso si es cursiva, no se puede escribir de un solo trazo.Cada MotionEvent.ACTION_UP teléfono Recognizer.recognize() Donde reiniciamos Ink.Stroke Después de recibir el resultado.Por lo tanto, en lugar de pasar las coordenadas de todos los subtrayectos, llamamos .recognize() Para cada subruta individual.
Este problema se puede aliviar agregando un comportamiento como «antirrebote», que evitará .recognize() Después de un cierto período de tiempo MotionEvent.ACTION_UP.
Agregar antirrebote
Para lograr el antirrebote, debemos cancelar todos Recognizer.recognize()Después de un cierto período de tiempo (compensación de fluctuación de fase) MotionEvent.ACTION_UPPuede haber una mejor manera de lograrlo, pero esta es la solución que se me ocurrió.
Agregamos un delay(offset) En la corrutina antes de la llamada Recognizer.recognize() existe MotionEvent.ACTION_UP. Entonces podemos cancelar la corrutina iniciada en el siguiente paso MotionEvent.ACTION_DOWN.
Si el usuario toca el Canvas dentro del retardo especificado, la corrutina iniciada se cancela, evitando así Recognizer.recognize()Esto permitirá a los usuarios agregar múltiples trazos siempre que comiencen a dibujar el siguiente trazo (activando el siguiente trazo) MotionEvent.ACTION_DOWN Dentro de este desplazamiento específico.
Al darse cuenta de que la traducción de texto es muy similar a lo anterior, usaremos la traducción en el dispositivo de MLKit. Como sugiere el nombre, el modelo de traducción no requiere que Internet se ejecute en su dispositivo, por lo que a veces puede ser un poco inexacto.
igual que DigitalInkRecognizer En tinta digital, tenemos Translator aquí. Esto maneja tanto la descarga de traducciones como las traducciones.Al inicializar Translator Debemos especificar el idioma de origen y el idioma de destino. El resto de la implementación se explica por sí mismo.
Se menciona claramente incluso en la documentación. .close() Objeto Translator & Recognizer que ya no se usa.Podemos agregar un observador del ciclo de vida y cerrar estos objetos. LifeCycle.Event.ON_STOP.








