部署基本的“Google 翻译”。app on Python 2 App Engine

1. 概览

这一系列的 Codelab(自定进度的动手教程)旨在帮助开发者了解在部署应用时可用的各种选项。在本 Codelab 中,您将学习如何将 Google Cloud Translation API 与 Python 搭配使用,并在本地运行或部署到 Cloud 无服务器计算平台(App Engine、Cloud Functions 或 Cloud Run)。本教程代码库中提供的示例应用可以通过至少 8 种不同的方式部署,只需进行一些细微的配置更改即可:

  1. 本地 Flask 服务器 (Python 2)
  2. 本地 Flask 服务器 (Python 3)
  3. App Engine(Python 2)
  4. App Engine (Python 3)
  5. Cloud Functions(Python 3)
  6. Cloud Run(通过 Docker 运行 Python 2)
  7. Cloud Run(通过 Docker 运行 Python 3)
  8. Cloud Run(通过 Cloud Buildpack 使用 Python 3)

此 Codelab 将重点介绍如何将此应用部署到上文中加粗的平台。

您将了解如何

所需条件

调查问卷

您打算如何使用本教程?

阅读并完成练习 仅阅读

您如何评价使用 Python 的体验?

新手水平 中等水平 熟练水平

您如何评价自己在使用 Google Cloud 服务方面的经验水平?

新手 中等 熟练

2. 设置和要求

自定进度的环境设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串,您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中必须是唯一的,并且不可变(一经设置便无法更改)。Cloud Console 会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(它通常标识为 PROJECT_ID),因此如果您不喜欢某个 ID,请再生成一个随机 ID,还可以尝试自己创建一个,并确认是否可用。然后,项目创建后,ID 会处于“冻结”状态。
  • 第三个值是一些 API 使用的项目编号。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud Console 中启用结算功能,才能使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有费用的话)。要关闭资源以避免产生超出本教程范围的费用,请按照此 Codelab 末尾提供的任何“清理”说明操作。Google Cloud 的新用户符合参与 $300 USD 免费试用计划的条件。

3. 启用 Translation API

对于我们的示例应用,您将改为按照下面提供的类似说明启用 Cloud Translation APIApp Engine 服务。

启用 Cloud API

简介

无论您想在应用中使用哪些 Google API,都必须启用这些 API。以下示例展示了启用 Cloud Vision API 的两种方法。了解如何启用一个 Cloud API 后,您就可以启用其他 API,因为流程类似。

方法 1:通过 Cloud Shell 或命令行界面

虽然通过 Cloud 控制台启用 API 更为常见,但有些开发者更喜欢通过命令行执行所有操作。为此,您需要查找 API 的“服务名称”。它看起来像网址:SERVICE_NAME.googleapis.com。您可以在支持的产品图表中找到这些产品,也可以使用 Google Discovery API 以编程方式查询这些产品。

掌握这些信息后,您可以使用 Cloud Shell(或安装了 gcloud 命令行工具的本地开发环境)启用 API,如下所示:

gcloud services enable SERVICE_NAME.googleapis.com

例如,以下命令会启用 Cloud Vision API:

gcloud services enable vision.googleapis.com

此命令会启用 App Engine:

gcloud services enable appengine.googleapis.com

您还可以通过一个请求启用多个 API。例如,以下命令行可启用 Cloud Run、Cloud Artifact Registry 和 Cloud Translation API:

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

方法 2:通过 Cloud 控制台

您还可以在 API 管理器中启用 Vision API。在 Cloud 控制台中,前往 API 管理器,然后选择

fb0f1d315f122d4a.png

如果您想启用 Cloud Vision API,请在搜索栏中开始输入“vision”,系统会显示与您输入内容匹配的所有内容:

2275786a24f8f204.png

选择要启用的 API,然后点击启用

2556f923b628e31.png

费用

虽然许多 Google API 可免费使用,但Google Cloud 产品和 API 并非免费。启用 Cloud API 时,系统可能会要求您提供有效的结算账号。不过,请务必注意,某些 Google Cloud 产品提供“始终免费”层级(按天/月),您必须超出此层级才能产生结算费用;否则,系统不会向您的信用卡(或指定的结算工具)收费。

用户应先查看任何 API 的价格信息,然后再进行启用,尤其是要注意该 API 是否提供免费层级,如果提供,具体是怎样的。如果您要启用 Cloud Vision API,请查看其价格信息页面。Cloud Vision 确实有免费配额,只要您在每月总用量不超过配额,就不会产生任何费用。

Google API 的价格和免费层级各不相同。示例:

不同 Google 产品的结算方式有所不同,因此请务必参阅 API 的文档了解相关信息。

摘要

现在,您已经了解了如何常规启用 Google API,请前往 API 管理中心同时启用 Cloud Translation API 和 App Engine 服务(如果您尚未启用)。前者是因为我们的应用将使用它,后者是因为您要部署 App Engine 应用。如果您更喜欢通过命令行执行此操作,请改为发出以下命令:

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

虽然“始终免费”层级的总摘要页面中未列出其每月配额,但Translation API 的价格页面指出,所有用户每月可获得固定数量的译文字符。如果您未达到该阈值,则不会产生任何 API 费用。如果还有任何其他与 Google Cloud 相关的扣款,我们会在最后的“清理”部分中加以说明。

4. 获取示例应用代码

在本地或 Cloud Shell(使用 git clone 命令)中克隆 代码库中的代码,或点击其绿色的 Code 按钮下载 ZIP 文件,如以下屏幕截图所示:

5cd6110c4414cf65.png

现在,您已经完成了所有准备工作,接下来请创建该文件夹的完整副本,以便完成本教程,因为本教程可能涉及删除或更改文件。如果您想进行其他部署,可以先复制原始项目,然后从头开始,这样就不必重新克隆或下载。

5. 示例应用导览

示例应用是一个简单的 Google 翻译派生应用,会提示用户输入英语文本,并接收该文本的相应西班牙语译文。现在,打开 main.py 文件,看看它是如何运作的。忽略关于许可的注释行,顶部和底部会如下所示:

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. 这些导入会引入 Flask 功能、google.auth 模块和 Cloud Translation API 客户端库。
  2. 全局变量代表 Flask 应用、Cloud 项目 ID、Translation API 客户端、Translation API 调用的父“位置路径”,以及源语言和目标语言。在本例中,它们分别是英语 (en) 和西班牙语 (es),但您可以随意将这些值更改为 Cloud Translation API 支持的其他语言代码
  3. 底部的大型 if 块在本地运行此应用教程中有所用途,它利用 Flask 开发服务器来提供我们的应用。此部分也适用于 Cloud Run 部署教程,以防 Web 服务器未捆绑到容器中。系统会提示您在容器中启用服务器捆绑,但如果您忽略了这一点,应用代码会回退到使用 Flask 开发服务器。(这不是 App Engine 或 Cloud Functions 的问题,因为它们是基于来源的平台,这意味着 Google Cloud 提供并运行默认的 Web 服务器。)

最后,在 main.py 中间是应用的核心,即 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)

主要函数负责接收用户输入,并调用 Translation API 来执行繁重工作。我们来详细了解一下:

  1. 使用 local_request 变量检查请求是否来自 Cloud Functions。Cloud Functions 会发送自己的 Flask Request 对象,而所有其他函数(在本地运行或部署到 App Engine 或 Cloud Run)都会直接从 Flask 获取请求对象。
  2. 重置表单的基本变量。这主要适用于 GET 请求,因为 POST 请求将有数据来替换这些值。
  3. 如果是 POST 请求,请提取要翻译的文本,并创建一个表示 API 元数据要求的 JSON 结构。然后调用该 API,如果用户使用的是较旧的库,则回退到该 API 的旧版本。
  4. 无论如何,请将实际结果 (POST) 或无数据 (GET) 格式化为模板上下文并进行渲染。

应用的可视部分位于模板 index.html 文件中。它会显示之前翻译过的所有内容(否则为空),后跟一个用于输入要翻译的内容的表单:

<!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. 安装本地软件包/依赖项(到 lib)

如前所述,该示例应用使用 Flask Micro Web 框架和 Python 版 Google Cloud Translation API 客户端库。使用以下 pip(或 pip3)命令安装和更新 pip 以及这对软件包:

pip install -t lib -r requirements.txt

运行上述注释后,您会看到安装输出,可能如下所示:

$ 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. 部署服务

如需将翻译服务部署到 Python 2 App Engine,请运行以下命令:

gcloud app deploy

输出应如下所示,并提供一些有关后续步骤的提示:

$ 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

现在,您的应用已面向全球发布,您应该能够通过部署输出中提供的网址(包含您的项目 ID)访问该应用:

da28f951c33a2c3d.png

翻译一些内容,看看效果如何!

d911984d15dd5ef9.png

8. 总结

恭喜!您已了解如何启用 Cloud Translation API、获取必要的凭据,以及如何将简单的 Web 应用部署到 Python 2 App Engine!如需详细了解此部署,请参阅代码库中的此表格

清理

借助 Cloud Translation API,您可以每月免费翻译固定数量的字符。App Engine 还有免费配额Cloud FunctionsCloud Run 也是如此。如果超出任一上限,您将需要支付费用。如果您打算继续学习下一个 Codelab,则无需关闭应用。

不过,如果您还不准备学习下一教程,或者担心互联网会发现您刚刚部署的应用,请停用 App Engine 应用删除 Cloud Functions 函数停用 Cloud Run 服务,以免产生费用。当您准备好进入下一个 Codelab 时,可以重新启用该功能。另一方面,如果您不打算继续使用此应用或其他 Codelab,并且想彻底删除所有内容,可以关闭项目

此外,部署到 Google Cloud 无服务器计算平台会产生少量构建和存储费用Cloud BuildCloud Storage 都有自己的免费配额。为了提高透明度,Cloud Build 会构建您的应用映像,然后将其存储在 Cloud Container Registry 或其后继产品 Artifact Registry 中。存储该图片会使用部分配额,将该图片传输到服务时也会使用部分网络出站流量。不过,您所在的地区可能不提供此类免费层级,因此请注意您的存储用量,以尽可能降低潜在费用。

9. 其他资源

在下一部分中,您可以找到其他阅读材料以及推荐的练习,以便巩固您在本教程中学到的知识。

其他研究

现在,您已经有了一些使用 Translation API 的经验,接下来我们再做一些额外的练习,以进一步提升您的技能。如需继续学习,请修改我们的示例应用,以执行以下操作:

  1. 完成此 Codelab 的所有其他版本,以便在本地运行或部署到 Google Cloud 无服务器计算平台(请参阅代码库自述文件)。
  2. 使用其他编程语言完成本教程。
  3. 更改此应用以支持不同的源语言或目标语言。
  4. 升级此应用,以便将文本翻译成多种语言;更改模板文件,以显示支持的目标语言的下拉菜单。

了解详情

Google App Engine

Google Cloud Functions

Google Cloud Run

Google Cloud Buildpacks、Container Registry、Artifact Registry

Google Cloud Translation 和 Google ML Kit

其他 Google Cloud 产品/页面

Python 和 Flask

许可

本教程已获得 Creative Commons Attribution 2.0 通用许可,而代码库中的源代码已获得 Apache 2 许可。