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

1. 概览

本系列 Codelab(自定进度的实操教程)旨在帮助开发者了解在部署应用时可以选择的各种方案。在此 Codelab 中,您将学习如何将 Google Cloud Translation API 与 Python 搭配使用,以及如何在本地运行或部署到 Cloud 无服务器计算平台(App Engine、Cloud Functions 或 Cloud Run)。只需对配置稍做更改,本教程的代码库中的示例应用就可以(至少)通过八种不同方式进行部署:

  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 Buildpacks 使用 Python 3)

此 Codelab 将重点介绍如何将该应用部署到上述以粗体显示的平台。

您将了解如何

所需条件

调查问卷

您打算如何使用本教程?

<ph type="x-smartling-placeholder"></ph> 阅读并完成练习 只读

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

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

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

<ph type="x-smartling-placeholder"></ph> 新手 中级 熟练

2. 设置和要求

自定进度的环境设置

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

96a9c957bc475304

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,都必须启用它们。以下示例展示了启用 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

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

2556f923b628e31

费用

虽然许多 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 命令),或通过其绿色的代码按钮下载 ZIP 文件,如以下屏幕截图所示:

5cd6110c4414cf65

现在您已具备所有条件,请创建该文件夹的完整副本以执行此特定教程,因为这可能涉及删除或更改文件。如果您想执行其他部署,可以复制原始部署以重新开始,这样就不必重新克隆或下载它。

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 客户端和父级“位置路径”翻译 API 调用,以及源语言和目标语言。在本示例中,语言为英语 (en) 和西班牙语 (es),但您可以随时将这些值更改为 Cloud Translation API 支持的其他语言代码。
  3. 在本地运行此应用的教程中使用底部的大 if 代码块,它利用 Flask 开发服务器为我们的应用提供支持。如果 Web 服务器未捆绑到容器中,则本部分也适用于 Cloud Run 部署教程。系统会要求您启用将服务器捆绑到容器中,但如果您忽略这一点,应用代码将回退到使用 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 请求对象中发送,而所有其他对象(在本地运行或者部署到 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 RegistryArtifact Registry(其后续版本)中。存储该映像会占用部分配额,以及在将该映像传输到服务时的网络出站流量。但是,如果您居住的区域没有这样的免费层级,请留意您的存储空间用量,以最大限度地降低潜在费用。

9. 其他资源

在以下部分中,您可以找到更多阅读材料和推荐的练习,扩充您完成本教程中学到的知识。

其他研究

现在,您已经掌握了 Translation API 的一些使用经验,接下来让我们做一些额外的练习来进一步培养您的技能。要继续您的学习路线,请修改我们的示例应用以执行以下操作:

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

了解详情

Google App Engine

Google Cloud Functions

Google Cloud Run

Google Cloud Buildpack、Container Registry、Artifact Registry

Google Cloud Translation 和 Google 机器学习套件

其他 Google Cloud 产品/页面

Python 和 Flask

许可

本教程依据知识共享署名 2.0 通用许可授权,而代码库中的源代码则根据 Apache 2 授权用户使用。