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

1. Descripción general

Esta serie de codelabs (instructivos prácticos y de autoaprendizaje) tiene como objetivo ayudar a los desarrolladores a comprender las diferentes opciones que tienen cuando implementan sus aplicaciones. En este codelab, aprenderás a usar la API de Google Cloud Translation con Python y a ejecutarla de forma local o implementarla en una plataforma de procesamiento 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 de (al menos) ocho maneras diferentes con solo cambios menores de configuración:

  1. Servidor Flask local (Python 2)
  2. Servidor 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 paquetes de compilación de Cloud)

Este codelab se enfoca en implementar esta app en las plataformas en negrita anteriores.

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 de Cloud habilitada para implementaciones basadas en la nube
  • Habilidades básicas de Python
  • Conocimiento práctico de los comandos básicos del sistema operativo

Encuesta

¿Cómo usarás este instructivo?

Leer y completar los ejercicios Solo leer

¿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. Habilita la API de Translation

En nuestra app de ejemplo, habilitarás la API de Cloud Translation y el servicio de App Engine con instrucciones similares a las que se proporcionan a continuación.

Habilita las APIs de Cloud

Introducción

Independientemente de la API de Google que quieras usar en tu aplicación, esta debe estar habilitada. En el siguiente ejemplo, se muestran dos maneras de habilitar la API de Cloud Vision. Después de aprender a habilitar una API de Cloud, podrás habilitar otras, ya que el proceso es similar.

Opción 1: Desde Cloud Shell o tu interfaz de línea de comandos

Si bien es más común habilitar las APIs desde la consola de Cloud, algunos desarrolladores prefieren hacerlo todo desde la línea de comandos. Para ello, debes buscar el "nombre del servicio" de una API. Se parece a una URL: SERVICE_NAME.googleapis.com. Puedes encontrar estos datos en el gráfico de productos compatibles o consultarlos de forma programática con la API de Google Discovery.

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

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, Artifact Registry de Cloud y la API de Cloud Translation:

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

Opción 2: Desde la consola de Cloud

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

fb0f1d315f122d4a.png

Si quieres habilitar la API de Cloud Vision, comienza a escribir “visión” en la barra de búsqueda y aparecerá todo lo que coincida con lo que ingresaste hasta el momento:

2275786a24f8f204.png

Selecciona la API que deseas 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 y las APIs de Google Cloud no es gratuito. 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 un nivel "Siempre gratis" (diario o mensual) que debes superar para generar cargos de facturación. De lo contrario, no se te cobrará a tu tarjeta de crédito (o instrumento de facturación especificado).

Los usuarios deben consultar la información de precios de cualquier API antes de habilitarla, en especial, si tiene un nivel gratuito y, de ser así, cuál es. Si habilitaras la API de Cloud Vision, deberías consultar la página Información de precios. Cloud Vision tiene una cuota gratuita y, siempre que no superes los límites en total (dentro de cada mes), no deberías incurrir en ningún cargo.

Los precios y los niveles gratuitos varían según 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 sabes cómo habilitar las APIs de Google en general, ve al Administrador de APIs y habilita la API de Cloud Translation y el servicio de App Engine (si aún no lo hiciste). La primera porque nuestra aplicación la usará y la segunda porque estás implementando una app de App Engine. Si prefieres hacerlo desde la línea de comandos, escribe este comando:

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

Si bien su cuota mensual no se indica en la página de resumen general del nivel "Siempre gratis", la página de precios de la API de Translation indica que todos los usuarios obtienen una cantidad fija de caracteres traducidos mensualmente. No deberías incurrir en ningún cargo de la API si te mantienes por debajo de ese límite. Si hay otros cargos relacionados con Google Cloud, se analizarán al final en la sección "Limpieza".

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

Clona el código en el repositorio de forma local o en Cloud Shell (con el comando git clone) o descarga el archivo ZIP desde el 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 realizar este instructivo específico, ya que es probable que debas borrar o cambiar los archivos. Si quieres realizar una implementación diferente, puedes comenzar de nuevo copiando el original para no tener que clonarlo ni volver a descargarlo.

5. Recorrido por la app de ejemplo

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

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 incluyen 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, la "ruta de ubicación" superior para las llamadas a la API de Translation y los idiomas de origen y destino. En este caso, son inglés (en) y español (es), pero no dudes en cambiar estos valores a otros códigos de idioma compatibles con la API de Cloud Translation.
  3. El bloque grande de if en la parte inferior se usa en el instructivo para ejecutar esta app de forma local. Utiliza el servidor de desarrollo de Flask para entregar nuestra app. Esta sección también está aquí para los instructivos de implementación de Cloud Run en caso de que el servidor web no esté incluido en el contenedor. Se te solicita que habilites el empaquetado del servidor en el contenedor, pero, en caso de que lo pases por alto, el código de la app volverá a usar el servidor de desarrollo de Flask. (No es un problema con App Engine o Cloud Functions, ya que son plataformas basadas en fuentes, lo que significa que Google Cloud proporciona y ejecuta un servidor web predeterminado).

Por último, en el medio de main.py, se encuentra 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 se encarga de tomar la entrada del usuario y llamar a la API de Translation para realizar el trabajo pesado. Veamos esto en detalle:

  1. Verifica si las solicitudes provienen de Cloud Functions con la variable local_request. Cloud Functions envía su propio objeto de solicitud de Flask, 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 de Flask.
  2. Restablece las variables básicas del formulario. Esto se aplica principalmente a las solicitudes GET, ya que las solicitudes POST tendrán datos que los reemplazarán.
  3. Si es una solicitud POST, toma el texto que se va a traducir y crea una estructura JSON que represente el requisito de metadatos de la API. Luego, llama a la API y vuelve a una versión anterior de la API si el usuario emplea una biblioteca más antigua.
  4. Independientemente de esto, da formato a los resultados reales (POST) o sin datos (GET) en el contexto de la plantilla y renderiza.

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

<!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. Instala paquetes o dependencias locales (en lib)

Como se mencionó anteriormente, la app de ejemplo usa el microframework web de Flask y la biblioteca cliente de la API de Google Cloud Translation para Python. Instala y actualiza pip junto con 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 verse de la siguiente manera:

$ 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 App Engine de Python 2, 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 de tu proyecto) que se proporcionó en el resultado de la implementación:

da28f951c33a2c3d.png

Traduce algo para ver cómo funciona.

d911984d15dd5ef9.png

8. Conclusión

¡Felicitaciones! Aprendiste a habilitar la API de Cloud Translation, obtener las credenciales necesarias y, luego, implementar una app web simple en Python 2 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, y lo mismo sucede con Cloud Functions y Cloud Run. Se te cobrarán cargos si se supera cualquiera de ellos. Si planeas continuar con el siguiente codelab, no es necesario que cierres la app.

Sin embargo, si aún no estás listo para continuar con el siguiente instructivo o te preocupa que Internet descubra la app que acabas de implementar, inhabilita tu app de App Engine, borra tu función de Cloud Functions o inhabilita tu servicio de Cloud Run para evitar que se apliquen 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 con otros codelabs y quieres 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 mayor transparencia, Cloud Build compila la imagen de tu aplicación, que luego se almacena en Cloud Container Registry o Artifact Registry, su sucesor. 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 tenga un nivel gratuito, por lo que debes tener en cuenta tu uso de almacenamiento para minimizar los posibles costos.

9. Recursos adicionales

En las siguientes secciones, encontrarás material de lectura adicional y ejercicios recomendados para aumentar los conocimientos que obtuviste al completar este instructivo.

Estudio adicional

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

  1. Completa todas las demás ediciones de este codelab para ejecutarlo de forma local o implementarlo en las plataformas de procesamiento sin servidores de Google Cloud (consulta el archivo readme del repositorio).
  2. Completa este instructivo con otro lenguaje de programación.
  3. Cambia esta aplicación para admitir diferentes idiomas de origen o destino.
  4. Actualiza esta aplicación para poder traducir texto a más de un idioma. Cambia el archivo de plantilla para que tenga un menú desplegable de los idiomas de destino compatibles.

Más información

Google App Engine

Google Cloud Functions

Google Cloud Run

Google Cloud Buildpacks, Container Registry y Artifact Registry

Traducción de Google Cloud y Google ML Kit

Otros productos o páginas de Google Cloud

Python y Flask

Licencia

Este instructivo está bajo la licencia Atribución 2.0 Genérica de Creative Commons, mientras que el código fuente del repositorio está bajo la licencia Apache 2.