Implementa un "Google Traductor" en Python 2 de App Engine

1. Descripción general

Esta serie de codelabs (instructivos prácticos de autoaprendizaje) tiene como objetivo ayudar a los desarrolladores a comprender las diversas opciones que tienen a la hora de implementar sus aplicaciones. En este codelab, aprenderás a usar la API de Google Cloud Translation con Python y a ejecutarla de forma local o a implementarla en una plataforma de computación sin servidores de Cloud (App Engine, Cloud Functions o Cloud Run). La app de ejemplo que se encuentra en el repositorio de este instructivo se puede implementar (al menos) de ocho maneras diferentes con solo cambios de configuración menores:

  1. Servidor de Flask local (Python 2)
  2. Servidor de Flask local (Python 3)
  3. App Engine (Python 2)
  4. App Engine (Python 3)
  5. Cloud Functions (Python 3)
  6. Cloud Run (Python 2 a través de Docker)
  7. Cloud Run (Python 3 a través de Docker)
  8. Cloud Run (Python 3 a través de Cloud Buildpacks)

Este codelab se enfoca en la implementación de esta app en las plataformas en negrita mencionadas anteriormente.

Obtendrás información para hacer las siguientes acciones

Requisitos

  • Un proyecto de Google Cloud con una cuenta de Facturación de Cloud activa
  • Flask instalado para ejecutarse de forma local o una plataforma de procesamiento sin servidores en la nube habilitada para implementaciones basadas en la nube
  • Habilidades básicas de Python
  • Tener conocimiento práctico de los comandos básicos del sistema operativo

Encuesta

¿Cómo usarás este instructivo?

Léelo y completa los ejercicios. Solo lectura .

¿Cómo calificarías tu experiencia en Python?

Principiante Intermedio Avanzado

¿Cómo calificarías tu experiencia en el uso de los servicios de Google Cloud?

Principiante Intermedio Avanzado .
.

2. Configuración y requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a Google Cloud Console y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una string de caracteres que no se utiliza en las API de Google y se puede actualizar en cualquier momento.
  • El ID del proyecto debe ser único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). Cloud Console genera automáticamente una string única, que, por lo general, no importa cuál sea. En la mayoría de los codelabs, debes hacer referencia al ID del proyecto (suele ser PROJECT_ID). Por lo tanto, si no te gusta, genera otro aleatorio o prueba con uno propio y comprueba si está disponible. Después de crear el proyecto, este ID se “congela” y no se puede cambiar.
  • Además, hay un tercer valor, el Número de proyecto, que usan algunas API. Obtén más información sobre estos tres valores en la documentación.
  1. A continuación, deberás habilitar la facturación en Cloud Console para usar las API o los recursos de Cloud. Ejecutar este codelab no debería costar mucho, tal vez nada. Si quieres cerrar los recursos para no se te facture más allá de este instructivo, sigue las instrucciones de “limpieza” que se encuentran al final del codelab. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de USD 300.

3. Habilitar la API de Translation

Para nuestra aplicación de muestra, habilitarás la API de Cloud Translation y el servicio de App Engine en su lugar mediante instrucciones similares que se proporcionan a continuación.

Habilita las APIs de Cloud

Introducción

Independientemente de la API de Google que desees usar en tu aplicación, estas deben estar habilitadas. En el siguiente ejemplo, se muestran dos formas de habilitar la API de Cloud Vision. Después de aprender a habilitar una API de Cloud, podrás habilitar otras APIs, ya que el proceso es similar.

Opción 1: En Cloud Shell o en la interfaz de línea de comandos

Si bien habilitar las APIs desde la consola de Cloud es más común, algunos desarrolladores prefieren hacer todo desde la línea de comandos. Para ello, debes buscar el “nombre de servicio” de una API. Parece una URL: SERVICE_NAME.googleapis.com. Puedes encontrarlos en el gráfico de productos admitidos o puedes buscarlos de manera programática con la API de Google Discovery.

Con esta información, puedes habilitar una API de la siguiente manera si usas Cloud Shell (o tu entorno de desarrollo local con la herramienta de línea de comandos de gcloud instalada):

gcloud services enable SERVICE_NAME.googleapis.com

Por ejemplo, este comando habilita la API de Cloud Vision:

gcloud services enable vision.googleapis.com

Este comando habilita App Engine:

gcloud services enable appengine.googleapis.com

También puedes habilitar varias APIs con una solicitud. Por ejemplo, esta línea de comandos habilita Cloud Run, Cloud Artifact Registry y la API de Cloud Translation:

gcloud services enable artifactregistry.googleapis.com run.googleapis.com translate.googleapis.com

Opción 2: En la consola de Cloud

También puedes habilitar la API de Vision en el Administrador de API. En la consola de Cloud, ve al Administrador de API y selecciona Biblioteca.

fb0f1d315f122d4a.png

Si quieres habilitar la API de Cloud Vision, comienza a escribir “vision”. en la barra de búsqueda, se mostrarán todos los elementos que coincidan con lo que ingresaste:

2275786a24f8f204.png

Selecciona la API que quieres habilitar y haz clic en Habilitar:

2556f923b628e31.png

Costo

Si bien muchas APIs de Google se pueden usar sin tarifas, el uso de los productos de Google Cloud y Las APIs no son gratuitas. Cuando habilites las APIs de Cloud, es posible que se te solicite una cuenta de facturación activa. Sin embargo, es importante tener en cuenta que algunos productos de Google Cloud cuentan con la función “Siempre gratuito” (diario o mensual), que deberás superar para generar cargos de facturación De lo contrario, no se realizará el cargo en tu tarjeta de crédito (o el instrumento de facturación especificado).

Los usuarios deben hacer referencia a la información de precios de cualquier API antes de habilitarla, en especial si tienen un nivel gratuito y, de ser así, qué es. Si estuvieras habilitando la API de Cloud Vision, consultarías la página de información de precios. Cloud Vision tiene una cuota gratuita y, si te mantienes dentro de los límites agregados (dentro de cada mes), no debes incurrir en cargos.

Los precios y los niveles gratuitos varían entre las APIs de Google. Ejemplos:

Los diferentes productos de Google se facturan de manera diferente, así que asegúrate de consultar la documentación de tu API para obtener esa información.

Resumen

Ahora que ya sabes cómo habilitar las APIs de Google en general, ve al Administrador de API y habilita la API de Cloud Translation y el servicio de App Engine (si aún no lo has hecho). La primera opción porque la usará nuestra aplicación y la segunda porque implementarás una app de App Engine. Si prefieres hacerlo desde la línea de comandos, ejecuta este comando en su lugar:

gcloud services enable appengine.googleapis.com translate.googleapis.com

Si bien su cuota mensual no aparece en la lista de la lista general "Siempre gratuito" nivel de resumen, la página de precios de la API de Translation indica que todos los usuarios reciben una cantidad fija de caracteres traducidos por mes. No se te debería cobrar ningún cargo a la API si te mantienes por debajo de ese umbral. Si hay otros cargos relacionados con Google Cloud, se analizarán al final de la sección “Limpieza” sección.

4. Obtén el código de la app de ejemplo

Clona el código del repositorio de forma local o en Cloud Shell (con el comando git clone), o descarga el archivo ZIP del botón verde Code, como se muestra en la siguiente captura de pantalla:

5cd6110c4414cf65.png

Ahora que tienes todo, crea una copia completa de la carpeta para hacer este instructivo específico, ya que es probable que implique borrar o cambiar los archivos. Si quieres realizar una implementación diferente, puedes comenzar de nuevo copiando la original para no tener que clonarla ni descargarla de nuevo.

5. Recorrido por la app de ejemplo

La app de ejemplo es un derivado sencillo de Google Traductor que les indica a los usuarios que ingresen un texto en inglés y reciban la traducción equivalente de ese texto en español. Ahora, abre el archivo main.py para que podamos ver cómo funciona. Si omites las líneas comentadas sobre las licencias, se verá de la siguiente manera en la parte inferior y superior:

from flask import Flask, render_template, request
import google.auth
from google.cloud import translate

app = Flask(__name__)
_, PROJECT_ID = google.auth.default()
TRANSLATE = translate.TranslationServiceClient()
PARENT = 'projects/{}'.format(PROJECT_ID)
SOURCE, TARGET = ('en', 'English'), ('es', 'Spanish')

# . . . [translate() function definition] . . .

if __name__ == '__main__':
    import os
    app.run(debug=True, threaded=True, host='0.0.0.0',
            port=int(os.environ.get('PORT', 8080)))
  1. Las importaciones aportan la funcionalidad de Flask, el módulo google.auth y la biblioteca cliente de la API de Cloud Translation.
  2. Las variables globales representan la app de Flask, el ID del proyecto de Cloud, el cliente de la API de Translation y la “ruta de ubicación” superior. para las llamadas a la API de Translation, así como los idiomas fuente y objetivo. En este caso, es inglés (en) y español (es), pero puedes cambiar estos valores a otros códigos de idioma compatibles con la API de Cloud Translation.
  3. El bloque if grande que aparece en la parte inferior se usa en el instructivo para ejecutar esta app de manera local; usa el servidor de desarrollo Flask para entregar la app. Esta sección también está disponible para los instructivos de implementación de Cloud Run en caso de que el servidor web no esté empaquetado en el contenedor. Se te solicita que habilites la agrupación del servidor en el contenedor, pero, en caso de que no la tengas en cuenta, el código de la app recurre al uso del servidor de desarrollo de Flask. No es un problema de App Engine ni de Cloud Functions porque son plataformas basadas en fuentes, lo que significa que Google Cloud proporciona y ejecuta un servidor web predeterminado.

Por último, en medio de main.py está el corazón de la aplicación, la función translate():

@app.route('/', methods=['GET', 'POST'])
def translate(gcf_request=None):
    """
    main handler - show form and possibly previous translation
    """

    # Flask Request object passed in for Cloud Functions
    # (use gcf_request for GCF but flask.request otherwise)
    local_request = gcf_request if gcf_request else request

    # reset all variables (GET)
    text = translated = None

    # if there is data to process (POST)
    if local_request.method == 'POST':
        text = local_request.form['text']
        data = {
            'contents': [text],
            'parent': PARENT,
            'target_language_code': TARGET[0],
        }
        # handle older call for backwards-compatibility
        try:
            rsp = TRANSLATE.translate_text(request=data)
        except TypeError:
            rsp = TRANSLATE.translate_text(**data)
        translated = rsp.translations[0].translated_text

    # create context & render template
    context = {
        'orig':  {'text': text, 'lc': SOURCE},
        'trans': {'text': translated, 'lc': TARGET},
    }
    return render_template('index.html', **context)

La función principal toma la entrada del usuario y llama a la API de Translation para realizar el trabajo pesado. Analicemos esto:

  1. Usa la variable local_request para verificar si las solicitudes provienen de Cloud Functions. Cloud Functions envía su propio objeto Flask Request, mientras que todos los demás (que se ejecutan de forma local o se implementan en App Engine o Cloud Run) obtendrán el objeto de solicitud directamente desde Flask.
  2. Restablece las variables básicas del formulario. Esto es principalmente para solicitudes GET, ya que las solicitudes POST tendrán datos que las reemplazarán.
  3. Si se trata de un POST, toma el texto que quieras traducir y crea una estructura JSON que represente el requisito de metadatos de la API. Luego, llama a la API y recurre a una versión anterior de la API si el usuario emplea una biblioteca antigua.
  4. En cualquier caso, formatea los resultados reales (POST) o ningún dato (GET) en el contexto y la renderización de la plantilla.

La parte visual de la aplicación se encuentra en el archivo de plantilla index.html. Muestra los resultados traducidos anteriormente (en blanco en caso contrario) seguidos del formulario en el que se solicita alguna traducción:

<!doctype html>
<html><head><title>My Google Translate 1990s</title><body>
<h2>My Google Translate (1990s edition)</h2>

{% if trans['text'] %}
    <h4>Previous translation</h4>
    <li><b>Original</b>:   {{ orig['text'] }}  (<i>{{ orig['lc'][0] }}</i>)</li>
    <li><b>Translated</b>: {{ trans['text'] }} (<i>{{ trans['lc'][0] }}</i>)</li>
{% endif %}

<h4>Enter <i>{{ orig['lc'][1] }}</i> text to translate to <i>{{ trans['lc'][1] }}</i>:</h4>
<form method="POST"><input name="text"><input type="submit"></form>
</body></html>

6. Cómo instalar paquetes o dependencias locales (en lib)

Como se mencionó anteriormente, la app de ejemplo usa el framework web micro Flask y la biblioteca cliente de la API de Google Cloud Translation para Python. Instala y actualiza pip además de este par de paquetes con este comando pip (o pip3):

pip install -t lib -r requirements.txt

Después de ejecutar el comentario anterior, verás el resultado de la instalación, que puede ser similar al siguiente:

$ pip install -t lib -r requirements.txt
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Collecting flask>=1.1.2
  Using cached Flask-1.1.4-py2.py3-none-any.whl (94 kB)
Collecting google-cloud-translate>=2.0.1
  Using cached google_cloud_translate-2.0.2-py2.py3-none-any.whl (91 kB)
Collecting click<8.0,>=5.1
  Using cached click-7.1.2-py2.py3-none-any.whl (82 kB)
Collecting Jinja2<3.0,>=2.10.1
  Using cached Jinja2-2.11.3-py2.py3-none-any.whl (125 kB)
Collecting Werkzeug<2.0,>=0.15
  Using cached Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB)
Collecting itsdangerous<2.0,>=0.24
  Using cached itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB)
Collecting google-api-core[grpc]<2.0.0dev,>=1.15.0
  Downloading google_api_core-1.29.0-py2.py3-none-any.whl (93 kB)
     |████████████████████████████████| 93 kB 2.1 MB/s
Collecting google-cloud-core<2.0dev,>=1.1.0
  Using cached google_cloud_core-1.6.0-py2.py3-none-any.whl (28 kB)
Collecting MarkupSafe>=0.23
  Using cached MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl (17 kB)
Collecting protobuf>=3.12.0
  Downloading protobuf-3.17.2-cp27-cp27m-macosx_10_9_x86_64.whl (958 kB)
     |████████████████████████████████| 958 kB 21.6 MB/s
Collecting futures>=3.2.0; python_version < "3.2"
  Using cached futures-3.3.0-py2-none-any.whl (16 kB)
Collecting six>=1.13.0
  Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting packaging>=14.3
  Using cached packaging-20.9-py2.py3-none-any.whl (40 kB)
Collecting googleapis-common-protos<2.0dev,>=1.6.0
  Using cached googleapis_common_protos-1.52.0-py2.py3-none-any.whl (100 kB)
Collecting requests<3.0.0dev,>=2.18.0
  Using cached requests-2.25.1-py2.py3-none-any.whl (61 kB)
Collecting google-auth<2.0dev,>=1.25.0
  Using cached google_auth-1.30.1-py2.py3-none-any.whl (146 kB)
Collecting pytz
  Using cached pytz-2021.1-py2.py3-none-any.whl (510 kB)
Collecting setuptools>=40.3.0
  Using cached setuptools-44.1.1-py2.py3-none-any.whl (583 kB)
Collecting grpcio<2.0dev,>=1.29.0; extra == "grpc"
  Using cached grpcio-1.38.0-cp27-cp27m-macosx_10_10_x86_64.whl (3.8 MB)
Collecting pyparsing>=2.0.2
  Using cached pyparsing-2.4.7-py2.py3-none-any.whl (67 kB)
Collecting chardet<5,>=3.0.2
  Using cached chardet-4.0.0-py2.py3-none-any.whl (178 kB)
Collecting urllib3<1.27,>=1.21.1
  Using cached urllib3-1.26.5-py2.py3-none-any.whl (138 kB)
Collecting idna<3,>=2.5
  Using cached idna-2.10-py2.py3-none-any.whl (58 kB)
Collecting certifi>=2017.4.17
  Downloading certifi-2021.5.30-py2.py3-none-any.whl (145 kB)
     |████████████████████████████████| 145 kB 61.1 MB/s
Collecting pyasn1-modules>=0.2.1
  Using cached pyasn1_modules-0.2.8-py2.py3-none-any.whl (155 kB)
Collecting rsa<4.6; python_version < "3.6"
  Using cached rsa-4.5-py2.py3-none-any.whl (36 kB)
Collecting cachetools<5.0,>=2.0.0
  Using cached cachetools-3.1.1-py2.py3-none-any.whl (11 kB)
Collecting enum34>=1.0.4; python_version < "3.4"
  Using cached enum34-1.1.10-py2-none-any.whl (11 kB)
Collecting pyasn1<0.5.0,>=0.4.6
  Using cached pyasn1-0.4.8-py2.py3-none-any.whl (77 kB)
Installing collected packages: click, MarkupSafe, Jinja2, Werkzeug, itsdangerous, flask, six, protobuf, futures, pyparsing, packaging, googleapis-common-protos, chardet, urllib3, idna, certifi, requests, pyasn1, pyasn1-modules, rsa, cachetools, setuptools, google-auth, pytz, enum34, grpcio, google-api-core, google-cloud-core, google-cloud-translate
ERROR: pip's legacy dependency resolver does not consider dependency conflicts when selecting packages. This behaviour is the source of the following dependency conflicts.
matplotlib 1.3.1 requires nose, which is not installed.
matplotlib 1.3.1 requires tornado, which is not installed.
Successfully installed Jinja2-2.11.3 MarkupSafe-1.1.1 Werkzeug-1.0.1 cachetools-3.1.1 certifi-2021.5.30 chardet-4.0.0 click-7.1.2 enum34-1.1.10 flask-1.1.4 futures-3.3.0 google-api-core-1.29.0 google-auth-1.30.1 google-cloud-core-1.6.0 google-cloud-translate-2.0.2 googleapis-common-protos-1.52.0 grpcio-1.38.0 idna-2.10 itsdangerous-1.1.0 packaging-20.9 protobuf-3.17.2 pyasn1-0.4.8 pyasn1-modules-0.2.8 pyparsing-2.4.7 pytz-2021.1 requests-2.25.1 rsa-4.5 setuptools-44.1.1 six-1.16.0 urllib3-1.26.5

7. Implemente el servicio

Para implementar tu servicio de traducción en Python 2 App Engine, ejecuta este comando:

gcloud app deploy

El resultado debería ser el siguiente y proporcionar algunas indicaciones para los próximos pasos:

$ gcloud app deploy
Services to deploy:

descriptor:      [/private/tmp/nebulous-serverless-python/app.yaml]
source:          [/private/tmp/nebulous-serverless-python]
target project:  [PROJECT_ID]
target service:  [default]
target version:  [20210422t161025]
target url:      [https://PROJECT_ID.appspot.com]


Do you want to continue (Y/n)?

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1290 files to Google Cloud Storage                       ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://PROJECT_ID.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s default

To view your application in the web browser run:
  $ gcloud app browse

Ahora que tu app está disponible en todo el mundo, deberías poder acceder a ella en la URL (que contiene el ID del proyecto) proporcionada en el resultado de tu implementación:

da28f951c33a2c3d.png

Traduce contenido para que funcione.

d911984d15dd5ef9.png

8. Conclusión

¡Felicitaciones! Aprendiste a habilitar la API de Cloud Translation, obtener las credenciales necesarias e implementar una aplicación web sencilla en Python 2 de App Engine. Puedes obtener más información sobre esta implementación en esta tabla del repositorio.

Limpia

La API de Cloud Translation te permite realizar una cantidad fija de caracteres traducidos por mes de forma gratuita. App Engine también tiene una cuota gratuita, al igual que Cloud Functions y Cloud Run. Se generarán cargos si se excede alguno de esos requisitos. Si planeas continuar con el siguiente codelab, no es necesario que cierres la app.

Sin embargo, si aún no estás listo para ir al siguiente instructivo o te preocupa que Internet descubra la app que acabas de implementar, inhabilita tu app de App Engine, borra tu Cloud Function o inhabilita tu servicio de Cloud Run para evitar que se generen cargos. Cuando estés listo para pasar al siguiente codelab, puedes volver a habilitarla. Por otro lado, si no vas a continuar con esta aplicación o algún otro codelab, y deseas borrar todo por completo, puedes cerrar tu proyecto.

Además, la implementación en una plataforma de procesamiento sin servidores de Google Cloud genera costos menores de compilación y almacenamiento. Cloud Build tiene su propia cuota gratuita, al igual que Cloud Storage. Para una mayor transparencia, Cloud Build compila la imagen de tu aplicación, que luego se almacena en Cloud Container Registry o Artifact Registry, su sucesora. El almacenamiento de esa imagen consume parte de esa cuota, al igual que la salida de red cuando se transfiere esa imagen al servicio. Sin embargo, es posible que vivas en una región que no cuenta con ese nivel gratuito, así que ten en cuenta el uso que haces del almacenamiento para minimizar posibles costos.

9. Recursos adicionales

En las siguientes secciones, encontrarás material de lectura adicional y ejercicios recomendados para aumentar tu conocimiento adquirido tras completar este tutorial.

Estudio adicional

Ahora que ya tienes experiencia con la API de Translation, realicemos algunos ejercicios adicionales para desarrollar aún más tus habilidades. Para continuar tu ruta de aprendizaje, modifica nuestra app de ejemplo para que realice lo siguiente:

  1. Completa todas las demás ediciones de este codelab para ejecutar de forma local o implementar en plataformas de computación sin servidores de Google Cloud (consulta README del repositorio).
  2. Completa este instructivo con otro lenguaje de programación.
  3. Cambia esta aplicación para que sea compatible con diferentes idiomas de origen u objetivo.
  4. Actualiza esta aplicación para poder traducir texto a más de un idioma. Cambia el archivo de plantilla para que se muestre un menú desplegable con los idiomas de destino admitidos.

Más información

Google App Engine

Google Cloud Functions

Google Cloud Run

Google Cloud Buildpacks, Container Registry y Artifact Registry

Google Cloud Translation y el kit de AA de Google

Otros productos o páginas de Google Cloud

Python y Flask

Licencia

Este instructivo cuenta con una licencia genérica de Creative Commons Attribution 2.0, mientras que el código fuente del repositorio está sujeto a Apache 2.