Создание и развертывание статического веб-приложения в Azure

В этом руководстве описано локальное создание и развертывание клиентского приложения React или TypeScript в виде статического веб-приложения Azure с помощью действия GitHub. Приложение React позволяет анализировать изображения с помощью Компьютерного зрения Cognitive Services.

Создание новой или использование существующей подписки Azure

Вам потребуется учетная запись Azure с активной подпиской. Создайте ее бесплатно.

Необходимые компоненты

  • Установите на локальный компьютер Node.js и npm.
  • Установите на локальный компьютер Visual Studio Code.
  • Средство Git для отправки данных в GitHub, по которым активируется действие GitHub.
  • Учетная запись GitHub для создания вилки репозитория и отправки данных.
  • Azure Cloud Shell можно использовать в среде Bash.
  • Вашей учетной записи Azure должна быть назначена роль участника Cognitive Services, чтобы вы могли принять условия использования искусственного интеллекта и создать ресурс. Чтобы назначить эту роль своей учетной записи, следуйте инструкциям, описанным в документации по назначению ролей, или обратитесь к администратору.

Что такое статическое веб-приложение Azure?

При создании статических веб-приложений вы можете настроить в Azure несколько разных параметров в зависимости от требуемой функциональности и степени контроля. В этом руководстве рассматривается самый простой вариант службы, в котором большинство параметров уже выбраны за вас, чтобы вы могли сосредоточиться на коде интерфейса, не отвлекаясь на среду размещения.

Приложение React (create-react-app) реализует следующие возможности:

  • отображение сообщения, если ключ и конечная точка Azure для Компьютерного зрения Cognitive Services не найдены;
  • Позволяет анализировать изображение с помощью Cognitive Services Компьютерное зрение
    • получение изображения для анализа по общедоступному URL-адресу или из коллекции;
    • После завершения анализа
      • Показать образ
      • отображение результатов от Компьютерного зрения в формате JSON.

Partial browser screenshot of React Cognitive Service Computer Vision sample results.

Чтобы развернуть статическое веб-приложение, используйте действие GitHub, которое начинается при отправке в определенную ветвь:

  • встраивает в сборку секреты GitHub, содержащие ключ и конечную точку для Компьютерного зрения;
  • компилирует клиент React (create-react-app);
  • перемещает полученные файлы в ресурс статического веб-приложения Azure.

1. Вилку примера репозитория

Создайте вилку репозитория, а не просто клонируйте его на локальный компьютер. Так вы получите собственный репозиторий GitHub, в который можно отправлять изменения.

  1. Откройте новое окно или вкладку браузера и войдите в GitHub.

  2. Перейдите к примеру репозитория GitHub.

    https://github.com/Azure-Samples/js-e2e-client-cognitive-services
    
  3. В верхней части страницы справа выберите команду Fork (Создать вилку).

  4. Выберите элемент Code (Код) и скопируйте URL-адрес расположения созданной вилки.

    Partial screenshot of GitHub website, select **Code** then copy the location for your fork.

2. Создание локальной среды разработки

  1. В окне терминала или bash скопируйте вилку на локальный компьютер. Замените YOUR-ACCOUNT-NAME именем учетной записи GitHub.

    git clone https://github.com/YOUR-ACCOUNT-NAME/js-e2e-client-cognitive-services
    
  2. Перейдите в новый каталог и установите зависимости.

    cd js-e2e-client-cognitive-services && npm install
    

    Этап установки устанавливает необходимые зависимости, включая @azure/cognitiveservices-computervision.

3. Запуск локального примера

  1. Запустите образец.

    npm start
    

    Partial browser screenshot of React Cognitive Service Computer Vision sample for image analysis before key and endpoint set.

  2. Остановите приложение. Закройте окно терминала или выполните в терминале команду control+c.

4. Создание группы ресурсов

В терминале или оболочке Bash введите команду Azure CLI для создания группы ресурсов Azure с именем rg-demo:

az group create \
    --location eastus \
    --name rg-demo \
    --subscription YOUR-SUBSCRIPTION-NAME-OR-ID

5. Создание ресурса Компьютерное зрение

Создание группы ресурсов позволяет вам с легкостью находить ресурсы и удалять их, когда они больше не нужны. Этот тип ресурса требует, чтобы вы приняли соглашение об ответственном использовании. Следующий список поможет вам узнать, как быстро создать правильный ресурс:

6. Создание первого ресурса Компьютерное зрение

Если это ваша первая служба искусственного интеллекта, необходимо создать службу на портале и принять соглашение об ответственном использовании в рамках процесса по созданию ресурса. Если для вас это не первый ресурс, которому требуется соглашение об ответственном использовании, можно создать ресурс с помощью Azure CLI (см. следующий раздел).

Следующая таблица поможет вам создать ресурс на портале Azure.

Параметр Значение
Группа ресурсов rg-demo
Имя. demo-ComputerVision
Sku S1
Местонахождение eastus

7. Создание дополнительного ресурса Компьютерное зрение

Выполните следующую команду, чтобы создать ресурс Компьютерного зрения:

az cognitiveservices account create \
    --name demo-ComputerVision \
    --resource-group rg-demo \
    --kind ComputerVision \
    --sku S1 \
    --location eastus \
    --yes

8. Получение конечной точки и ключей ресурсов Компьютерное зрение

  1. В результатах найдите и скопируйте ключ properties.endpoint. Позже он вам понадобится.

    ...
    "properties":{
        ...
        "endpoint": "https://eastus.api.cognitive.microsoft.com/",
        ...
    }
    ...
    
  2. Выполните приведенную ниже команду, чтобы получить ключи.

    az cognitiveservices account keys list \
    --name demo-ComputerVision \
    --resource-group rg-demo
    
  3. Скопируйте один из ключей, который пригодится чуть позже.

    {
      "key1": "8eb7f878bdce4e96b26c89b2b8d05319",
      "key2": "c2067cea18254bdda71c8ba6428c1e1a"
    }
    

9. Добавление переменных среды в локальную среду

Чтобы использовать ресурс, в локальном коде нужно знать ключ и адрес конечной точки. В нашей базе кода они хранятся в переменных среды:

  • REACT_APP_AZURE_COMPUTER_VISION_KEY
  • REACT_APP_AZURE_COMPUTER_VISION_ENDPOINT
  1. Выполните приведенную ниже команду, чтобы добавить эти переменные в среду.

    export REACT_APP_AZURE_COMPUTER_VISION_KEY="REPLACE-WITH-YOUR-KEY"
    export REACT_APP_AZURE_COMPUTER_VISION_ENDPOINT="REPLACE-WITH-YOUR-ENDPOINT"
    

10. Добавление переменных среды в удаленную среду

При работе со статическими веб-приложениями Azure необходимо передавать из действия GitHub в статическое веб-приложение переменные среды, например со значениями секретов. Действие GitHub обеспечивает сборку приложения, включая в нее ключ и конечную точку Компьютерного зрения, полученные в виде секретов GitHub для репозитория. Затем код вместе с переменными среды отправляется в статическое веб-приложение.

  1. В веб-браузере откройте репозиторий GitHub и последовательно выберите элементы Параметры, Секреты и Новый секрет репозитория.

    Partial browser screenshot of GitHub repository, creating new repository secret.

  2. Введите имя и значение конечной точки, которые уже использовалась в предыдущем разделе. Затем создайте другой секрет с тем же именем и значением ключа, которые использовались в предыдущем разделе.

    Enter the same name and value for the endpoint. Then create another secret with the same name and value for the key.

11. Запуск локального приложения react с помощью ресурса ComputerVision

  1. Запустите приложение повторно в командной строке:

    npm start
    

    Partial browser screenshot of React Cognitive Service Computer Vision sample ready for URL or press enter.

  2. Оставьте текстовое поле пустым, чтобы выбрать изображение из каталога по умолчанию, и нажмите кнопку Анализ.

    Partial browser screenshot of React Cognitive Service Computer Vision sample results.

    Изображение выбирается случайным образом из каталога изображений, который определен в ./src/DefaultImages.js.

  3. Повторно нажимайте кнопку Analyze (Анализ), чтобы увидеть другие изображения и результаты для них.

12. Отправка локальной ветви в GitHub

В терминале Visual Studio Code отправьте локальную ветвь main в удаленный репозиторий.

git push origin main

Не нужно фиксировать изменения, так как они еще не внесены.

13. Создание ресурса статического веб-приложения

  1. Выберите значок Azure, щелкните правой кнопкой мыши службу Static Web Apps (Статические веб-приложения) и выберите элемент Create Static Web App (Advanced) (Создать статическое веб-приложение (Расширенное)).

    Visual Studio Code screenshot with Visual Studio extension

  2. Если во всплывающем окне появится запрос на продолжение работы в ветви main, нажмите кнопку Continue (Продолжить).

  3. Поочередно введите значения в следующие поля (по одному за раз):

    Имя поля значение
    Выберите группу ресурсов для новых ресурсов. Выберите группу ресурсов, созданную для ресурса ComputerVision, demo-ComputerVision.
    Введите имя нового статического веб-приложения. Demo-ComputerVisionAnalyzer
    Выбор ценового уровня Выберите бесплатно.
    Выберите расположение для кода приложения. Выберите то же расположение, которое вы выбрали при создании группы ресурсов eastus.
    Choose build preset to configure default project structure (Выберите предустановку сборки, чтобы настроить структуру проекта по умолчанию). React
    Выберите расположение для кода приложения. /
    Введите расположение для кода Функций Azure. Присвойте значение по умолчанию.
    Введите путь к выходным данным сборки относительно расположения приложения. build

14. Обновление действия GitHub с помощью переменных секретной среды

Ключ и конечная точка Компьютерного зрения находятся в коллекции секретов репозитория, но пока не переданы в действие GitHub. На этом шаге к действию добавляются ключ и конечная точка.

  1. Получите изменения, внесенные при создании ресурса Azure, чтобы получить файл действий GitHub.

    git pull origin main
    
  2. В редакторе Visual Studio Code измените файл действий GitHub, расположенный в ./.github/workflows/, добавив в него секреты.

    name: Azure Static Web Apps CI/CD
    
    on:
      push:
        branches:
          - from-local
      pull_request:
        types: [opened, synchronize, reopened, closed]
        branches:
          - from-local
    
    jobs:
      build_and_deploy_job:
        if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
        runs-on: ubuntu-latest
        name: Build and Deploy Job
        steps:
          - uses: actions/checkout@v2
            with:
              submodules: true
          - name: Build And Deploy
            id: builddeploy
            uses: Azure/static-web-apps-deploy@v0.0.1-preview
            with:
              azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_RANDOM_NAME_HERE }}
              repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
              action: "upload"
              ###### Repository/Build Configurations - These values can be configured to match you app requirements. ######
              # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
              app_location: "/" # App source code path
              api_location: "api" # Api source code path - optional
              output_location: "build" # Built app content directory - optional
              ###### End of Repository/Build Configurations ######
            env:
              REACT_APP_AZURE_COMPUTER_VISION_ENDPOINT: ${{secrets.REACT_APP_AZURE_COMPUTER_VISION_ENDPOINT}}
              REACT_APP_AZURE_COMPUTER_VISION_KEY:  ${{secrets.REACT_APP_AZURE_COMPUTER_VISION_KEY}}
    
      close_pull_request_job:
        if: github.event_name == 'pull_request' && github.event.action == 'closed'
        runs-on: ubuntu-latest
        name: Close Pull Request Job
        steps:
          - name: Close Pull Request
            id: closepullrequest
            uses: Azure/static-web-apps-deploy@v0.0.1-preview
            with:
              azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_RANDOM_NAME_HERE }}
              action: "close"
    
  3. Добавьте и зафиксируйте изменения в локальной ветви main.

    git add . && git commit -m "add secrets to action"
    
  4. Отправьте изменения в удаленный репозиторий. Будет активировано новое действие сборки и развертывания в статическое веб-приложение Azure.

    git push origin main
    

15. Просмотр процесса сборки GitHub Action

  1. В веб-браузере откройте репозиторий GitHub для этого руководства и выберите Actions (Действия).

  2. Выберите верхнюю сборку в списке, затем щелкните элемент Build and Deploy Job (Задание сборки и развертывания), чтобы просмотреть сведения о процессе сборки. Дождитесь, пока процесс Build And Deploy (Сборка и развертывание) успешно завершится.

     Select the top build in the list, then select `Build and Deploy Job` on the left-side menu to watch the build process. Wait until the build successfully finishes.

16. Просмотр удаленного статического веб-сайта Azure в браузере

  1. В Visual Studio Code выберите значок Azure в крайнем меню справа. Затем выберите созданное статическое веб-приложение, щелкните правой кнопкой мыши элемент Browse site (Обзор сайта) и выберите команду Open (Открыть), чтобы просмотреть общедоступный статический веб-сайт.

Select `Browse site`, then select `Open` to view the public static web site.

Кроме того, URL-адрес этого сайта можно также найти:

  • на странице Обзор для ресурса на портале Azure;
  • в выходных данных сборки и развертывания из действия GitHub, где URL-адрес сайта выводится в самом конце скрипта.

17. Очистка ресурсов для статического веб-приложения

Завершив работу с этим руководством, удалите группу ресурсов с ресурсом Компьютерного зрения и статическим веб-приложением, чтобы с вас не взималась плата за использование.

В VS Code выберите обозреватель Azure, правой кнопкой мыши щелкните группу ресурсов из приведенного для подписки списка, а затем выберите Удалить.

Partial screen shot of VS Code, selecting resource group from list of resource groups, then right-clicking to select `Delete`.

Код: добавление Компьютерное зрение в локальное приложение React

С помощью npm добавьте Компьютерное зрение в файл package.json.

npm install @azure/cognitiveservices-computervision 

Код: добавление кода Компьютерное зрение в виде отдельного модуля

Код Компьютерного зрения размещается в отдельном файле с именем ./src/azure-cognitiveservices-computervision.js. Здесь выделена функция main этого модуля.

// ./src/azure-cognitiveservices-computervision.js

// Azure SDK client libraries
import { ComputerVisionClient } from '@azure/cognitiveservices-computervision';
import { ApiKeyCredentials } from '@azure/ms-rest-js';

// List of sample images to use in demo
import RandomImageUrl from './DefaultImages';

// Authentication requirements
const key = process.env.REACT_APP_AZURE_COMPUTER_VISION_KEY;
const endpoint = process.env.REACT_APP_AZURE_COMPUTER_VISION_ENDPOINT;

console.log(`key = ${key}`)
console.log(`endpoint = ${endpoint}`)

// Cognitive service features
const visualFeatures = [
    "ImageType",
    "Faces",
    "Adult",
    "Categories",
    "Color",
    "Tags",
    "Description",
    "Objects",
    "Brands"
];

export const isConfigured = () => {
    const result = (key && endpoint && (key.length > 0) && (endpoint.length > 0)) ? true : false;
    console.log(`key = ${key}`)
    console.log(`endpoint = ${endpoint}`)
    console.log(`ComputerVision isConfigured = ${result}`)
    return result;
}

// Computer Vision detected Printed Text
const includesText = async (tags) => {
    return tags.filter((el) => {
        return el.name.toLowerCase() === "text";
    });
}
// Computer Vision detected Handwriting
const includesHandwriting = async (tags) => {
    return tags.filter((el) => {
        return el.name.toLowerCase() === "handwriting";
    });
}
// Wait for text detection to succeed
const wait = (timeout) => {
    return new Promise(resolve => {
        setTimeout(resolve, timeout);
    });
}

// Analyze Image from URL
export const computerVision = async (url) => {

    // authenticate to Azure service
    const computerVisionClient = new ComputerVisionClient(
        new ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': key } }), endpoint);

    // get image URL - entered in form or random from Default Images
    const urlToAnalyze = url || RandomImageUrl();
    
    // analyze image
    const analysis = await computerVisionClient.analyzeImage(urlToAnalyze, { visualFeatures });

    // text detected - what does it say and where is it
    if (includesText(analysis.tags) || includesHandwriting(analysis.tags)) {
        analysis.text = await readTextFromURL(computerVisionClient, urlToAnalyze);
    }

    // all information about image
    return { "URL": urlToAnalyze, ...analysis};
}
// analyze text in image
const readTextFromURL = async (client, url) => {
    
    let result = await client.read(url);
    let operationID = result.operationLocation.split('/').slice(-1)[0];

    // Wait for read recognition to complete
    // result.status is initially undefined, since it's the result of read
    const start = Date.now();
    console.log(`${start} -${result?.status} `);
    
    while (result.status !== "succeeded") {
        await wait(500);
        console.log(`${Date.now() - start} -${result?.status} `);
        result = await client.getReadResult(operationID);
    }
    
    // Return the first page of result. 
    // Replace[0] with the desired page if this is a multi-page file such as .pdf or.tiff.
    return result.analyzeResult; 
}

Код: добавление каталога изображений в виде отдельного модуля

Это приложение выбирает случайное изображение из каталога, если пользователь не ввел URL-адрес изображения. Здесь выделена функция случайного выбора

// ./src/DefaultImages.js

const describeURL = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/celebrities.jpg';
const categoryURLImage = 'https://moderatorsampleimages.blob.core.windows.net/samples/sample16.png';
const tagsURL = 'https://moderatorsampleimages.blob.core.windows.net/samples/sample16.png';
const objectURL = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-node-sdk-samples/master/Data/image.jpg';
const brandURLImage = 'https://docs.microsoft.com/en-us/azure/cognitive-services/computer-vision/images/red-shirt-logo.jpg';
const facesImageURL = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/faces.jpg';
const printedTextSampleURL = 'https://moderatorsampleimages.blob.core.windows.net/samples/sample2.jpg';
const multiLingualTextURL = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/MultiLingual.png';
const adultURLImage = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/celebrities.jpg';
const colorURLImage = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/celebrities.jpg';
// don't use with picture analysis
// eslint-disable-next-line
const mixedMultiPagePDFURL = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/MultiPageHandwrittenForm.pdf';
const domainURLImage = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-sample-data-files/master/ComputerVision/Images/landmark.jpg';
const typeURLImage = 'https://raw.githubusercontent.com/Azure-Samples/cognitive-services-python-sdk-samples/master/samples/vision/images/make_things_happen.jpg';

const DefaultImages = [
    describeURL,
    categoryURLImage,
    tagsURL,
    objectURL,
    brandURLImage,
    facesImageURL,
    adultURLImage,
    colorURLImage,
    domainURLImage,
    typeURLImage,
    printedTextSampleURL,
    multiLingualTextURL,
    //mixedMultiPagePDFURL
];

const RandomImageUrl = () => {
    return DefaultImages[Math.floor(Math.random() * Math.floor(DefaultImages.length))];
}

export default RandomImageUrl;

Код: добавление пользовательского модуля Компьютерное зрение в приложение React

Добавьте методы в файл React app.js. Здесь выделены фрагменты анализа изображения и отображения результатов.

// ./src/App.js

import React, { useState } from 'react';
import './App.css';
import { computerVision, isConfigured as ComputerVisionIsConfigured } from './azure-cognitiveservices-computervision';

function App() {

  const [fileSelected, setFileSelected] = useState(null);
  const [analysis, setAnalysis] = useState(null);
  const [processing, setProcessing] = useState(false);
  
  const handleChange = (e) => {
    setFileSelected(e.target.value)
  }
  const onFileUrlEntered = (e) => {

    // hold UI
    setProcessing(true);
    setAnalysis(null);

    computerVision(fileSelected || null).then((item) => {
      // reset state/form
      setAnalysis(item);
      setFileSelected("");
      setProcessing(false);
    });

  };

  // Display JSON data in readable format
  const PrettyPrintJson = (data) => {
    return (<div><pre>{JSON.stringify(data, null, 2)}</pre></div>);
  }

  const DisplayResults = () => {
    return (
      <div>
        <h2>Computer Vision Analysis</h2>
        <div><img src={analysis.URL} height="200" border="1" alt={(analysis.description && analysis.description.captions && analysis.description.captions[0].text ? analysis.description.captions[0].text : "can't find caption")} /></div>
        {PrettyPrintJson(analysis)}
      </div>
    )
  };
  
  const Analyze = () => {
    return (
    <div>
      <h1>Analyze image</h1>
      {!processing &&
        <div>
          <div>
            <label>URL</label>
            <input type="text" placeholder="Enter URL or leave empty for random image from collection" size="50" onChange={handleChange}></input>
          </div>
          <button onClick={onFileUrlEntered}>Analyze</button>
        </div>
      }
      {processing && <div>Processing</div>}
      <hr />
      {analysis && DisplayResults()}
      </div>
    )
  }
  
  const CantAnalyze = () => {
    return (
      <div>Key and/or endpoint not configured in ./azure-cognitiveservices-computervision.js</div>
    )
  }
  
  function Render() {
    const ready = ComputerVisionIsConfigured();
    if (ready) {
      return <Analyze />;
    }
    return <CantAnalyze />;
  }

  return (
    <div>
      {Render()}
    </div>
    
  );
}

export default App;

Следующие шаги