使用 Python 和 Flask 生成 AI Web 应用

简介

使用人工智能 (AI) 创建 Web 应用不需要涉及大量代码或从头开始创建服务。 假设我们想要创建一个可以为用户翻译文本的网站。

对于前端,我们所需要的应能够让我们不必经历诸多麻烦即可集成服务。 Flask 之类的框架就是很好的选择。 Flask 的创建者描述其为“微框架”,这意味着该框架会提供所需核心服务(例如路由和模板化),但在其他方面则允许使用应用程序所需的任何后端服务。 Flask 还是轻量级框架,可快速进行设置和部署。 我们不需要数据库或任何精致复杂的内容。 我们只需要一个框架来创建 UI,并能够调用后端服务。

对于后端,你可以使用一组 AI 服务(称为 Azure 认知服务),而不是自己创建机器学习模型。 这些服务可以通过 SDK 或 HTTP 调用访问。 我们可以使用翻译器服务来满足翻译文本的主要目标。

我们将探讨 Flask 和翻译器服务。 我们将了解如何创建一款 Web 应用来将文本翻译成各种语言。

设置开发环境

若要开始用 Python 编写 Flask 应用程序,我们需要设置开发环境,这将需要安装几个项目。 幸运的是,我们要使用的工具都相对通用

安装 Python

若要完成本单元的学习,你的计算机上必须安装 Python 3.6 或更高版本。 你可能已经安装了 Python,特别是在你已经使用过它的情况下。 可以通过执行下面的其中一条命令来确认是否已安装:

# Windows:
python --version
​
#macOS or Linux
python3 --version
复制代码

如果已安装 Python,则输出将显示 Python 版本号。如果没有的话请去官网安装.

创建项目目录

在你选择的位置创建目录。 该目录将作为你的项目目录,其中将包含我们要创建的所有代码。 可以使用下面的其中一条命令从命令或终端窗口创建目录:

# Windows
md contoso
cd contoso
​
## macOS or Linux
mkdir contoso
cd contoso
复制代码

创建 Python 虚拟环境

Python 虚拟环境并不一定像听起来那么复杂。 虚拟环境不是创建虚拟机或容器,而是一个包含运行应用程序所需的所有库的文件夹(包括 Python 运行时本身)。 利用虚拟环境,我们使应用程序实现模块化,这样我们就能让应用程序彼此独立并避免出现版本问题。 作为最佳做法,在使用 Python 时,应该始终使用虚拟环境。

为使用虚拟环境,我们将创建并激活虚拟环境。 我们使用 venv 模块来创建虚拟环境,该模块在先前的 Python 安装说明中已安装。 激活虚拟环境时,我们会告诉系统将我们创建的文件夹用于其所有的 Python 需求。

# Windows
# Create the environment
python -m venv venv
# Activate the environment
.\venv\scripts\activate
​
# macOS or Linux
# Create the environment
python3 -m venv venv
# Activate the environment
source ./venv/bin/activate
复制代码

安装 Flask 和其他库

随着虚拟环境的创建和激活,我们现在可以安装 Flask,这是网站所需的库。 我们将遵循常见约定来安装 Flask,即创建一个“requirements.txt”文件。 “requirements.txt”文件本身并不特殊;它是一个文本文件,其中列出了应用程序所需的库。 但这是开发人员通常使用的约定,可使管理依赖大量库的应用程序变得更轻松。

在后面的练习中,我们将使用几个其他库,包括请求(用于调用翻译器服务)和 python-dotenv(用于管理密钥)。 虽然我们现在还不需要这些库,但现在安装会让这一过程更轻松一些。

  1. 在命令或终端窗口中,运行以下命令以在 Visual Studio Code 中打开目录:

       code .
    复制代码
  2. 在 Visual Studio Code 中的“资源管理器”窗口中,选择“新建文件”

    显示 Visual Studio Code 中的“新建文件”按钮的屏幕截图。

    如果没有安装 Vscode 那么只需要在项目目录下 做第三步即可

  3. 将文件命名为 requirements.txt,然后添加以下文本:

    flask
    python-dotenv
    requests
    复制代码
  4. 在 Mac 上,通过单击“Ctrl-S”或“Cmd-S”来保存文件

  5. 返回到命令或终端窗口,使用 pip 运行以下命令来执行安装:

    pip install -r requirements.txt
    复制代码

该命令下载所需的库及其依赖项。

如果 pip 不是最新版本,则可能会收到错误消息。 按照错误消息中的说明执行升级。 此模块不要求升级。

如果一切顺利, 你现在已经设置了开发环境!

Flask 基础知识

Flask 是一种开源 Web“微框架”。 当创建者使用“微框架”这一术语时,他们是指框架将执行 Web 框架所需的任务,但其中不包含高级功能,或其他应用程序必须遵循才能正常工作的特定要求。 这种方法使 Flask 非常灵活,并十分适合用作现有后端或 API(如认知服务)的前端!

在使用任何框架创建 Web 应用时,我们都需要了解几个核心概念:路由、方法和模板化。 在编写代码前,我们先来了解这些概念。

使用路由响应用户请求

在使用 Web 应用时,用户通过浏览到不同的统一资源定位器(即 URL)来表明自己要执行的操作或正在查找的信息。 用户可以直接输入地址(比如 https://adventure-works.com),也可以选择链接或包含相应 URL 的按钮。 在电子商务网站上,你可能会看到如下 URL:

  • 主页:https://adventure-works.com/
  • 小组件详细信息:https://adventure-works.com/products/widget
  • 完成购买:https://adventure-works.com/cart/buy

作为开发人员,我们实际上无需担心 URL 的第一部分或域(本例中的“adventure-works.com”)。 我们的应用程序将根据域名后面的任何内容来执行操作,从 / 开始。 域名后面的部分称为“路由”。

路由是操作的路径。 与点击移动应用中的按钮类似,路由指示用户想要执行的操作。 我们将在 Web 应用中注册不同的路由,以响应应用程序支持的各种请求。

在我们的应用程序中,我们通过提供一个函数来指示要如何响应特定路由请求。 路由是到函数的映射。 当我们考虑编写一般代码时,此概念相对直观。 当我们想要执行特定操作时,就会调用函数。 我们的用户将执行完全相同的操作! 不过他们将通过访问路由来完成此操作。

创建 Web 应用时,有许多可用方法,但最常见的两种方法(也是我们只关注的两种)是“GET”和“POST”。 GET 通常表示用户正在请求信息,而 POST 表示用户需要向我们发送信息并接收响应。

使用 GET 和 POST 的常见应用程序流围绕使用表单展开。 假设我们创建了一款应用程序,其中用户想要注册邮件列表:

  1. 用户通过 GET 访问注册表单
  2. 用户完成表单,并选择“提交”按钮
  3. 表单中的信息通过 POST 发送回服务器
  4. 向用户返回“成功”消息

或如你所料,用户并没有直接指明自己要使用的谓词,谓词由应用程序控制。 一般来说,如果用户通过键入 URL 或选择链接直接导航到 URL,则使用 GET 访问该页面。 当该用户选择表单的按钮时,通常会通过 POST 发送信息。

模板

超文本标记语言 (HTML) 是用于构造浏览器上显示的信息的语言,而级联样式表 (CSS) 则用于管理样式和布局。 在创建应用程序时,大多数 HTML 都是静态的,这意味着该语言不会改变。 然而,为使页面具有动态性,我们需要能够以编程方式将信息放入 HTML 页面。 几乎每个 Web 框架都可通过模板来满足这一需求。

借助模板,你可以编写核心 HTML(或模板)并指示动态信息的占位符。 占位符最常见的语法或许是 {{ }}。 Flask 的模板引擎 Jinja 会使用这种语法。

HTML复制

<h1>Welcome, {{ name }}</h1>
复制代码

在前面的例子中,我们用到了 h1(标头)的 HTML,其中包含我们要显示的文本。 {{ name }} 表示要在“欢迎使用”之后显示一个名为 name 的变量。 通过这种语法,我们可以使用现有技能编写 HTML,并根据需要注入动态信息。

创建应用

我们将以迭代方式创建应用程序,在创建过程中重点关注特定的概念。 首先,我们将为应用程序创建登陆页面,该页面将显示用户要使用的表单。

通常,Flask 应用程序的入口点是名为“app.py”的文件。 我们将遵循这一约定并创建应用程序的核心。 我们将执行以下步骤:

  1. 创建核心应用程序
  2. 为应用程序添加路由
  3. 为网站创建 HTML 模板
  4. 测试应用程序

创建核心应用程序

新建文件 来创建名为“app.py”的新文件

  1. 添加代码以创建 Flask 应用程序

    Python复制

    from flask import Flask, redirect, url_for, request, render_template, session
    
    app = Flask(__name__)
    复制代码

导入语句包含对 Flask 的引用,这是所有 Flask 应用程序的核心。 当我们想返回 HTML 时,我们将在一段时间内使用 render_template

app 将是我们的核心应用程序。 在下一步中,我们将使用它来注册路由。

添加路由

应用程序将使用一个路由 - /。 此路由有时称为“默认”或“索引”路由,因为在用户不提供域或服务器名称之外的任何内容时,就会使用该路由。

将以下代码添加到“app.py”末尾

Python复制

@app.route('/', methods=['GET'])
def index():
    return render_template('index.html')
复制代码

通过 @app.route,我们可以指定要创建的路由。 路径将是 /,这是默认路由。 我们指出这将用于 GET。 如果 / 收到 GET 请求,Flask 将自动调用修饰器下面直接声明的函数,我们的示例中为 index。 在 index 的正文中,我们表示将向用户返回一个名为“index.html”的 HTML 模板。

为表单创建 HTML 模板

Flask 的模板引擎 Jinja 非常关注 HTML。 因此,我们可以使用所有现有的 HTML 技能和工具。 我们将使用启动来布置页面,使其更美观。 通过启动,我们将在 HTML 上使用不同的 CSS 类。 如果不熟悉启动,则可以忽略这些类而专注于 HTML(这是真正重要的部分)。

Flask 的模板需要在名为“模板”的文件夹中创建,这很合适。 让我们创建文件夹、必要的文件并添加 HTML。

  1. 通过在 Visual Studio Code 的“资源管理器”工具中选择“新建文件夹”,创建一个名为“模板”的新文件夹

  2. 选择创建的“模板”文件夹,然后选择“新建文件”将文件添加到该文件夹中

  3. 将该文件命名为“index.html”

  4. 添加以下 HTML

    HTML复制

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
            integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
        <title>Translator</title>
    </head>
    <body>
        <div class="container">
            <h1>Translation service</h1>
            <div>Enter the text you wish to translate, choose the language, and click Translate!</div>
            <div>
                <form method="POST">
                    <div class="form-group">
                        <textarea name="text" cols="20" rows="10" class="form-control"></textarea>
                    </div>
                    <div class="form-group">
                        <label for="language">Language:</label>
                        <select name="language" class="form-control">
                            <option value="en">English</option>
                            <option value="it">Italian</option>
                            <option value="ja">Japanese</option>
                            <option value="ru">Russian</option>
                            <option value="de">German</option>
                        </select>
                    </div>
                    <div>
                        <button type="submit" class="btn btn-success">Translate!</button>
                    </div>
                </form>
            </div>
        </div>
    </body>
    </html>
    复制代码

以上 HTML 中的核心组成部分是用户希望翻译的文本的 textarea,以及用户将用来指示目标语言的下拉列表 (select)。 如果要添加更多语言,则可以参考受支持语言列表,获取其他选项。 将 value 属性设置为语言代码,例如,“pl”表示波兰语。

测试应用程序

创建初始站点后,就该对其进行测试了! 我们将使用 Visual Studio Code 中的集成终端,让这一过程更轻松一些。

  1. 在 Mac 上,选择 Ctrl- 或 Cmd- 来打开集成终端

  2. 运行以下命令将 Flask 运行时设置为开发,这意味着服务器将在每次更改时自动重载

    Bash复制

    # Windows
    set FLASK_ENV=development
    
    # Linux/macOS
    export FLASK_ENV=development
    复制代码
  3. 运行应用程序!

    Bash复制

    flask run
    复制代码
  4. 通过导航到 http://localhost:5000,在浏览器中打开应用程序

应该会看到这样网页

image.png

应看到显示的表单。 祝贺!

翻译

虽然使用机器学习或人工智能的解决方案越来越普遍,但从头开始创建仍很困难。 幸运的是,很多解决方案已经开发出来,我们可以像访问任何应用程序编程接口 (API) 一样访问这些解决方案。 这种方法使我们能够专注于代码,而不是复杂的建模。

Azure 提供了一组名为认知服务的的产品/服务,其中包括计算机视觉、语音转文本、文本转语音以及文本翻译服务。 可以通过软件开发工具包 (SDK) 访问这些服务中的任意一项,也可以通过调用其他 HTTP 终结点的相同方式对其进行调用。

若要使用认知服务,你需要一个 Azure 帐户。 如果不熟悉 Azure,可以免费注册,其中包含 200 美元的免费额度(针对前 30 天)。 如果你是学生,可以注册面向学生的 Azure,其中包含 100 美元(期限为 12 个月)可使用额度,以及一系列其他免费服务。

翻译器服务

翻译器服务(认知服务的一部分)将在数十种语言之间进行互译。 该服务可自动检测出源语言,并可在一次调用中翻译成多种目标语言。 调用翻译器服务的方式与调用任何其他 HTTP 终结点的方式相同。 使用 Python 时,通常通过“请求”库来完成此操作,这是我们返回代码时将使用的库。

密钥管理

若要调用翻译器服务(或任何其他认知服务),我们将需要密钥。 每次访问服务时都将使用此密钥。 密钥类似于密码。 任何有权使用密钥的人都可以调用此服务,如果我们使用的是付费版本,就可能会产生一大笔费用!

在进行开发工作时,一种很好的解决方案可用于保护密钥,那就是使用名为 python-dotenv 的库,通常称为 dotenv。 使用 dotenv 时,我们会创建一个名为“.env”的文件,其中包含我们不希望作为源代码一部分的键/值对。 当我们将代码推送到 GitHub 时,便将确保该文件列在 gitignore 文件中,这样就不会意外将其公开发布。

 创建翻译器服务

获取翻译器服务的密钥。 如前文所述,我们需要一个 Azure 帐户。 我们将使用 Azure 门户创建密钥,并将其存储在应用程序的“.env”文件中。

获取翻译器服务密钥

  1. 浏览到 Azure 门户

  2. 选择“创建资源”

    显示 Azure 门户中“创建资源”选项的屏幕截图

  3. 在“搜索”框中,输入“翻译器”

  4. 选择“翻译器”

Fill out the "Create Translator" form with the following values:

  • Subscription: your subscription

  • Resource group:

    • Select "New"
    • Name: flask-ai
  • Resource group area : select a nearby area

  • Resource area : select the same area as above

  • Name : a unique value, such as ai-yourname

  • Pricing Tier : Free F0

  1. 选择“查看 + 创建”
  2. 选择“创建”
  3. 资源将在几分钟后创建
  4. 选择“转到资源”
  5. 选择“资源管理”下左侧的“密钥和终结点”

在“密钥 1”旁边,选择“复制到剪贴板”

创建用于存储密钥的 .env 文件

  1. 返回到 Visual Studio Code,通过选择“新建文件”并将其命名为“.env”,在应用程序的根目录中新建一个文件

  2. 将以下文本粘贴到“.env”中

    KEY=your_key
    ENDPOINT=your_endpoint
    LOCATION=your_location
    复制代码
  3. 替换占位符

    • 用上面复制的密钥替换占位符 your_key
    • 用 Azure 中的终结点替换占位符 your_endpoint
    • 用 Azure 中的位置替换占位符 your_location
  4. 你的“.env”文件应该如下所示(使用你的值):

    text复制

    KEY=00d09299d68548d646c097488f7d9be9
    ENDPOINT=https://api.cognitive.microsofttranslator.com/
    LOCATION=westus2
    复制代码

    调用翻译器服务

随着我们在 Azure 上创建的后端翻译器服务以及存储的变量已准备就绪,我们将重点转移到如何向应用程序添加必要逻辑和模板来翻译文本。 我们将执行以下步骤:

  1. 添加代码以调用服务
  2. 创建模板以显示结果
  3. 测试应用程序

添加代码以调用服务

app.py 包含应用程序的逻辑。 我们将为将要使用的库添加几项必需导入内容,然后添加响应用户的新路由。

  1. 在 app.py 的最顶端,添加以下代码行:

    import requests, os, uuid, json
    from dotenv import load_dotenv
    load_dotenv()
    复制代码

顶部一行将导入我们稍后在调用翻译器服务时使用的库。 我们还从 dotenv 导入 load_dotenv 并执行函数,该函数将从 .env 加载值。

  1. 在 app.py 的底部,添加以下代码行,创建用于翻译文本的路由和逻辑:

    @app.route('/', methods=['POST'])
    def index_post():
        # Read the values from the form
        original_text = request.form['text']
        target_language = request.form['language']
    
        # Load the values from .env
        key = os.environ['KEY']
        endpoint = os.environ['ENDPOINT']
        location = os.environ['LOCATION']
    
        # Indicate that we want to translate and the API version (3.0) and the target language
        path = '/translate?api-version=3.0'
        # Add the target language parameter
        target_language_parameter = '&to=' + target_language
        # Create the full URL
        constructed_url = endpoint + path + target_language_parameter
    
        # Set up the header information, which includes our subscription key
        headers = {
            'Ocp-Apim-Subscription-Key': key,
            'Ocp-Apim-Subscription-Region': location,
            'Content-type': 'application/json',
            'X-ClientTraceId': str(uuid.uuid4())
        }
    
        # Create the body of the request with the text to be translated
        body = [{ 'text': original_text }]
    
        # Make the call using post
        translator_request = requests.post(constructed_url, headers=headers, json=body)
        # Retrieve the JSON response
        translator_response = translator_request.json()
        # Retrieve the translation
        translated_text = translator_response[0]['translations'][0]['text']
    
        # Call render template, passing the translated text,
        # original text, and target language to the template
        return render_template(
            'results.html',
            translated_text=translated_text,
            original_text=original_text,
            target_language=target_language
        )
    复制代码

代码添加有注释,说明正在执行的步骤。 大致来看,我们的代码将执行以下操作:

  1. 读取用户输入的文本,以及用户在表单上选择的语言
  2. 从“.env”文件读取之前创建的环境变量
  3. 创建调用翻译器服务所需的路径,该服务包括目标语言(自动检测源语言)
  4. 创建标头信息,包括翻译器服务的密钥、服务的位置和翻译的任意 ID
  5. 创建请求的正文,其中包括要翻译的文本
  6. 在 requests 上调用 post 以调用翻译器服务
  7. 从服务器检索 JSON 响应,其中包括翻译后的文本
  8. 检索翻译后的文本(请参阅以下注释)
  9. 调用 render_template 以显示响应页

调用翻译器服务时,可以在一次调用中将多个语句翻译成多种语言。 因此,服务返回的 JSON 包含很多信息,我们只需要其中一小部分。 因此,我们需要往下细分才能获得翻译的文本。

具体而言,我们需要读取第一个结果,然后读取到 translations 的集合(第一次翻译),然后读取到 text。 这是通过调用完成的:translator_response[0]['translations'][0]['text']

[
  {
    "detectedLanguage": {
      "language": "en",
      "score": 1.0
    },
    "translations": [
      {
        "text": "これはテストです",
        "to": "ja"
      }
    ]
  }
]
复制代码

创建模板以显示结果

让我们为“结果”页创建 HTML 模板。

  1. 在 Visual Studio Code 中的“Explorer”工具中选择“模板”,在“模板”中新建一个文件。 然后选择“新建文件”

  2. 将文件命名为 results.html

  3. 将以下 HTML 添加到 results.html 中

    HTML复制

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
            integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
        <title>Result</title>
    </head>
    <body>
        <div class="container">
            <h2>Results</h2>
            <div>
                <strong>Original text:</strong> {{ original_text }}
            </div>
            <div>
                <strong>Translated text:</strong> {{ translated_text }}
            </div>
            <div>
                <strong>Target language code:</strong> {{ target_language }}
            </div>
            <div>
                <a href="{{ url_for('index') }}">Try another one!</a>
            </div>
        </div>
    </body>
    </html>
    复制代码

你会注意到,我们访问了 original_texttranslated_text 和 target_language,这些均使用 {{ }} 在 render_template 中作为命名参数传递。 此操作告知 Flask 将内容呈现为纯文本。 我们还要使用 url_for('index') 创建返回默认页面的链接。 虽然从技术上讲,我们可以键入原始页面的路径,但是使用 url_for 会告知 Flask 使用我们提供的名称(本例中为 index)读取函数的路径。 如果我们重新排列站点,则为链接生成的 URL 将始终有效。

测试页面

返回到 Visual Studio Code 中的集成终端(在 Mac 上可使用 Ctrl- 或 Cmd- 重新将其打开)。 如果站点当前正在运行,则我们需要停止并重启该站点,以便应用程序读取环境变量。

  1. 使用 Ctrl-C 停止 Flask 应用程序
  2. 执行命令 flask run 以重启服务
  3. 浏览到 http://localhost:5000 以测试应用程序
  4. 在文本区域输入文本,选择一种语言,然后选择“翻译”

image.png

image.png

猜你喜欢

转载自juejin.im/post/7041844091667087397