1. Overview
This series of codelabs (self-paced, hands-on tutorials) aims to help developers understand the various options they have when deploying their applications. In this codelab, you will learn how to use the Google Cloud Translation API with Python and either run locally or deploy to a Cloud serverless compute platform (App Engine, Cloud Functions, or Cloud Run). The sample app found in this tutorial's repo can be deployed (at least) eight different ways with only minor configuration changes:
- Local Flask server (Python 2)
- Local Flask server (Python 3)
- App Engine (Python 2)
- App Engine (Python 3)
- Cloud Functions (Python 3)
- Cloud Run (Python 2 via Docker)
- Cloud Run (Python 3 via Docker)
- Cloud Run (Python 3 via Cloud Buildpacks)
This codelab focuses on deploying this app to the bolded platform(s) above.
You'll learn how to
- Use Google Cloud APIs, specifically the Cloud Translation API (advanced/v3)
- Run a basic web application locally or deploy to a Cloud severless compute platform
What you'll need
- A Google Cloud project with an active Cloud Billing account
- Flask installed for running locally, or a Cloud severless compute platform enabled for cloud-based deployments
- Basic Python skills
- Working knowledge of basic operating system commands
Survey
How will you use this tutorial?
How would you rate your experience with Python?
How would you rate your experience with using Google Cloud services?
2. Setup and requirements
Self-paced environment setup
- Sign-in to the Google Cloud Console and create a new project or reuse an existing one. If you don't already have a Gmail or Google Workspace account, you must create one.
- The Project name is the display name for this project's participants. It is a character string not used by Google APIs, and you can update it at any time.
- The Project ID must be unique across all Google Cloud projects and is immutable (cannot be changed after it has been set). The Cloud Console auto-generates a unique string; usually you don't care what it is. In most codelabs, you'll need to reference the Project ID (and it is typically identified as
PROJECT_ID
), so if you don't like it, generate another random one, or, you can try your own and see if it's available. Then it's "frozen" after the project is created. - There is a third value, a Project Number which some APIs use. Learn more about all three of these values in the documentation.
- Next, you'll need to enable billing in the Cloud Console in order to use Cloud resources/APIs. Running through this codelab shouldn't cost much, if anything at all. To shut down resources so you don't incur billing beyond this tutorial, follow any "clean-up" instructions found at the end of the codelab. New users of Google Cloud are eligible for the $300 USD Free Trial program.
3. Enable Translation API
For our sample app, you'll enable the Cloud Translation API and the App Engine service instead using similar instructions provided below.
Enabling Cloud APIs
Introduction
Regardless of which Google API you want to use in your application, they must be enabled. The following example shows two ways to enable the Cloud Vision API. After you learn how to enable one Cloud API, you'll be able to enable other APIs because the process is similar.
Option 1: From Cloud Shell or your command-line interface
While enabling APIs from the Cloud Console is more common, some developers prefer doing everything from the command line. To do so, you need to look up an API's "service name." It looks like a URL: SERVICE_NAME
.googleapis.com
. You can find these in the Supported products chart, or you can programmatically query for them with the Google Discovery API.
Armed with this information, using Cloud Shell (or your local development environment with the gcloud
command-line tool installed), you can enable an API, as follows:
gcloud services enable SERVICE_NAME.googleapis.com
For example, this command enables the Cloud Vision API:
gcloud services enable vision.googleapis.com
This command enables App Engine:
gcloud services enable appengine.googleapis.com
You can also enable multiple APIs with one request. For example, this command line enables Cloud Run, Cloud Artifact Registry, and the Cloud Translation API:
gcloud services enable artifactregistry.googleapis.com run.googleapis.com translate.googleapis.com
Option 2: From the Cloud Console
You can also enable the Vision API in the API Manager. From the Cloud Console, go to API Manager and select Library.
If you wanted to enable the Cloud Vision API, start entering "vision" in the search bar, and anything that matches what you've entered so far will appear:
Select the API you're seeking to enable and click Enable:
Cost
While many Google APIs can be used without fees, use of Google Cloud products & APIs is not free. When enabling Cloud APIs, you may be asked for an active billing account. It is, however, important to note that some Google Cloud products feature an "Always Free" tier (daily/monthly), which you have to exceed in order to incur billing charges; otherwise, your credit card (or specified billing instrument) won't be charged.
Users should reference the pricing information for any API before enabling, especially noting whether it has a free tier, and if so, what it is. If you were enabling the Cloud Vision API, you would check its pricing information page. Cloud Vision does have a free quota, and so long as you stay within its limits in aggregate (within each month), you should not incur any charges.
Pricing and free tiers vary between Google APIs. Examples:
- Google Cloud/GCP — each product is billed differently and are generally pay per vCPU cycle, storage consumer, memory usage, or pay-per-use; see free tier information above.
- Google Maps — features a suite of APIs and offers users an overall $200USD free monthly credit.
- Google Workspace (formerly G Suite) APIs — provides free usage (up to certain limits) covered by a Workspace monthly subscription fee, so there's no direct billing for use of the Gmail, Google Drive, Calendar, Docs, Sheets, and Slides APIs.
Different Google products are billed differently, so be sure to reference your API's documentation for that information.
Summary
Now that you know how to enable Google APIs in general, please go to the API Manager and enable both the Cloud Translation API and App Engine service (if you haven't already), the former because our application will use it, and the latter because you're deploying an App Engine app. If you prefer to do it from the command-line, issue this command instead:
gcloud services enable appengine.googleapis.com translate.googleapis.com
While its monthly quota isn't listed in the overall "Always Free" tier summary page, the Translation API's pricing page states all users get a fixed amount of translated characters monthly. You shouldn't incur any charges from the API if you stay below that threshold. If there are any other Google Cloud related charges, they will be discussed at the end in the "Clean up" section.
4. Get the sample app code
Clone the code in the repo locally or in Cloud Shell (using the git clone
command), or download the ZIP file from its green Code button as shown in the following screenshot:
Now that you have everything, create a full copy of the folder to do this specific tutorial, because it will likely involve deleting or changing the files. If you want to do a different deployment, you can start over by copying the original so you don't have to clone or download it again.
5. Tour of sample app
The sample app is a simple Google Translate derivative that prompts users to enter text in English and receive the equivalent translation of that text in Spanish. Now open the main.py
file so we can see how it works. Omitting the commented lines about licensing, it looks like this at the top and bottom:
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)))
- The imports bring in Flask functionality, the
google.auth
module, and the Cloud Translation API client library. - The global variables represent the Flask app, the Cloud project ID, the Translation API client, the parent "location path" for Translation API calls, and the source and target languages. In this case, it's English (
en
) and Spanish (es
), but feel free to change these values to other language codes supported by the Cloud Translation API. - The large
if
block at the bottom is used in the tutorial for running this app locally—it utilizes the Flask development server to serve our app. This section is also here for the Cloud Run deployment tutorials in case the web server isn't bundled into the container. You are asked to enable bundling the server in the container, but in case you overlook this, the app code falls back to using the Flask development server. (It is not an issue with App Engine or Cloud Functions because those are sourced-based platforms, meaning Google Cloud provides and runs a default web server.)
Finally, in the middle of main.py
is the heart of the application, the translate()
function:
@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)
The primary function does the work of taking the user input, and calling the Translation API to do the heavy-lifting. Let's break it down:
- Check to see if requests are coming from Cloud Functions using the
local_request
variable. Cloud Functions sends in its own Flask Request object whereas all others (running locally or deploying to App Engine or Cloud Run) will get the request object directly from Flask. - Reset the basic variables for the form. This is primarily for GET requests as POST requests will have data that replace these.
- If it's a POST, grab the text to translate, and create a JSON structure representing the API metadata requirement. Then call the API, falling back to a previous version of the API if the user is employing an older library.
- Regardless, format the actual results (POST) or no data (GET) into the template context and render.
The visual part of the application is in the template index.html
file. It shows any previously translated results (blank otherwise) followed by the form asking for something to translate:
<!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. Install local packages/dependencies (into lib)
As previously mentioned, the sample app uses the Flask micro web framework and the Google Cloud Translation API client library for Python. Install and update pip
plus this pair of packages with this pip
(or pip3
) command:
pip install -t lib -r requirements.txt
After running the above comment, you'll see the installation output which may look something like this:
$ 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. Deploy the service
To deploy your translation service to Python 2 App Engine, run this command:
gcloud app deploy
The output should look as follows, and provide some prompts for next steps:
$ 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
Now that your app is available globally around the world, you should be able to reach it at the URL (containing your project ID) provided in your deployment output:
Translate something to see it work!
8. Conclusion
Congratulations! You've learned how to enable the Cloud Translation API, get the necessary credentials, and deploy a simple web app to Python 2 App Engine! You can learn more about this deployment from this table in the repo.
Clean up
The Cloud Translation API lets you perform a fixed amount of translated characters per month for free. App Engine also has a free quota, and the same goes for Cloud Functions and Cloud Run. You'll incur charges if either are exceeded. If you plan to continue to the next codelab, you don't have to shut down your app.
However, if you're not ready to go to the next tutorial yet or are concerned that the internet discovers the app that you've just deployed, disable your App Engine app, delete your Cloud Function, or disable your Cloud Run service to avoid incurring charges. When you're ready to move onto the next codelab, you can re-enable it. On the other hand, if you're not going to continue with this application or other codelabs and want to delete everything completely, you can shut down your project.
Also, deploying to a Google Cloud serverless compute platform incurs minor build and storage costs. Cloud Build has its own free quota as does Cloud Storage. For greater transparency, Cloud Build builds your application image, which is then stored in either the Cloud Container Registry or Artifact Registry, its successor. Storage of that image uses up some of that quota as does network egress when transferring that image to the service. However, you might live in a region that does not have such a free tier, so be aware of your storage usage to minimize potential costs.
9. Additional resources
In the following sections, you can find additional reading material as well as recommended exercises to augment your knowledge gained from completing this tutorial.
Additional study
Now that you have some experience with the Translation API under your belt, let's do some additional exercises to further develop your skills. To continue your learning path, modify our sample app to do the following:
- Complete all the other editions of this codelab for running locally or deploying to Google Cloud serverless compute platforms (see repo README).
- Complete this tutorial using another programming language.
- Change this application to support different source or target languages.
- Upgrade this application to be able to translate text into more than one language; change the template file to have a pulldown of supported target languages.
Learn more
Google App Engine
- App Engine home page
- App Engine documentation
- Python 3 App Engine quickstart
- Default service accounts for App Engine
- Python 2 App Engine (Standard) runtime
- Python 3 App Engine (Standard) runtime
- Differences between Python 2 & 3 App Engine (Standard) runtimes
- Python 2 to 3 App Engine (Standard) migration guide
Google Cloud Functions
- Cloud Functions home page
- Cloud Functions documentation
- Python Cloud Functions quickstart
- Default service accounts for Cloud Functions
Google Cloud Run
- Cloud Run home page
- Cloud Run documentation
- Python Cloud Run quickstart
- Default service accounts for Cloud Run
Google Cloud Buildpacks, Container Registry, Artifact Registry
- Cloud Buildpacks announcement
- Cloud Buildpacks repo
- Cloud Artifact Registry home page
- Cloud Artifact Registry documentation
- Cloud Container Registry home page
- Cloud Container Registry documentation
Google Cloud Translation and Google ML Kit
- Cloud Translation home page
- Cloud Translation documentation
- Translation API pricing page
- All Cloud AI/ML "building block" APIs
- Google ML Kit (Cloud AI/ML APIs subset for mobile)
- Google ML Kit Translation API
Other Google Cloud products/pages
- Google Cloud Python support
- Google Cloud client libraries
- Google Cloud "Always Free" tier
- All Google Cloud documentation
Python and Flask
License
This tutorial is licensed under a Creative Commons Attribution 2.0 Generic License while the source code in the repo is licensed under Apache 2.