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.pointerInteropFilter
tenemosMotionEvent
Similar a enandroid.view.View
Toque el monitor. - Por conveniencia, creé
sealed class DrawEvent
Esto se asignará a la correspondienteMotionEvent
. remember
estaPath
Objeto, porque no cambia la reorganización.Establezca el valor enmutableStateOf
En 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
.MotionEvent
Luego 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.JA
DigitalInkRecognizer
: Esto necesita ser generadoInk.Stroke
Como 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.Builder
MotionEvent.ACTION_UP
: Indica que el usuario ha dejado de tocar el lienzo, indicando así el final del dibujo.Ahora podemos construir el generadoInk.Stroke
Y pasarlo aRecognizer.recognize()
.
existeonSuccess
Recuperamos el resultado de la predicción (RecognitionResult.candidates
) show.existeonComplete
Fueron puestosInk.Stroke.Builder
Empiece 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_UP
Puede 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
.