Criar e implantar um aplicativo Web estático no Azure

Neste tutorial, crie e implante localmente um aplicativo cliente em React/TypeScript para um aplicativo Web estático do Azure com uma ação do GitHub. O aplicativo React permite que você analise uma imagem com a Pesquisa Visual Computacional dos Serviços Cognitivos.

Criar ou usar uma assinatura existente do Azure

Você precisará de uma conta de usuário do Azure com uma assinatura ativa. Crie um gratuitamente.

Pré-requisitos

  • Node.js e npm – instalados em seu computador local.
  • Visual Studio Code – instalado no computador local.
  • Git – usado para enviar por push para o GitHub, o que ativa a ação do GitHub.
  • Conta do GitHub – para criar fork e enviar por push para um repositório
  • Use o Azure Cloud Shell usando o ambiente bash.
  • Sua conta do Azure deve ter a função Colaborador dos Serviços Cognitivos atribuída para que você concorde com os termos e condições da IA responsável e crie um recurso. Para que essa função seja atribuída à sua conta, siga as etapas descritas na documentação Atribuir funções ou entre em contato com o administrador.

O que é um aplicativo Web estático do Azure

Ao criar aplicativos Web estáticos, você tem várias opções no Azure, com base no grau de funcionalidade e controle de seu interesse. Este tutorial se concentra no serviço mais fácil, com muitas das opções feitas para você, para que você possa se concentrar no código de front-end e não no ambiente de hospedagem.

O React (create-react-app) oferece a seguinte funcionalidade:

  • Exibir uma mensagem se a chave e o ponto de extremidade do Azure para a Pesquisa Visual Computacional dos Serviços Cognitivos não forem encontrados
  • Permite analisar uma imagem com o Cognitive Services Computer Vision
    • Inserir uma URL de imagem pública ou analisar imagem de uma coleção
    • Quando a análise estiver concluída
      • Exibir imagem
      • Exibir resultados em JSON da Pesquisa Visual Computacional

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

Para implantar o aplicativo Web estático, use uma ação do GitHub, que começa quando ocorre um push para uma ramificação específica:

  • Insere segredos do GitHub para chave e ponto de extremidade da Pesquisa Visual Computacional no build
  • Cria o cliente React (create-react-app)
  • Move os arquivos resultantes para o recurso de aplicativo Web estático do Azure

1. Garfe o repositório de amostra

Crie um fork do repositório em vez de apenas cloná-lo no computador local, para ter seu próprio repositório do GitHub para o qual enviar as alterações por push.

  1. Abra uma janela ou guia separada do navegador e entre no GitHub.

  2. Navegue até o repositório de exemplo do GitHub.

    https://github.com/Azure-Samples/js-e2e-client-cognitive-services
    
  3. Na seção superior direita da página, selecione Criar fork.

  4. Selecione Código e, em seguida, copie a URL do local para seu fork.

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

2. Criar um ambiente de desenvolvimento local

  1. Em uma janela de terminal ou bash, clone o fork no computador local. Substitua YOUR-ACCOUNT-NAME pelo nome da sua conta do GitHub.

    git clone https://github.com/YOUR-ACCOUNT-NAME/js-e2e-client-cognitive-services
    
  2. Altere para o novo diretório e instale as dependências.

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

    A etapa de instalação instala as dependências necessárias, incluindo @azure/cognitiveservices-computervision.

3. Execute a amostra local

  1. Execute o exemplo.

    npm start
    

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

  2. Interrompa o aplicativo. Feche a janela do terminal ou use control+c no terminal.

4. Crie seu grupo de recursos

Em um shell de terminal ou do bash, insira o comando CLI do Azure para criar um grupo de recursos do Azure, com o nome rg-demo:

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

5. Crie um recurso de Visão Computacional

A criação de um grupo de recursos permite que você encontre facilmente os recursos e exclua-os quando terminar. Esse tipo de recurso requer que você concorde com o contrato de Uso Responsável. Use a seguinte lista para saber como você pode criar rapidamente o recurso correto:

6. Crie seu primeiro recurso de Visão Computacional

Se esse for seu primeiro serviço de IA, você precisará criar o serviço por meio do portal e concordar com o contrato de Uso Responsável, como parte da criação do recurso. Se esse não for seu primeiro recurso que exige o contrato de Uso Responsável, você poderá criar o recurso com a CLI do Azure, encontrado na próxima seção.

Use a tabela a seguir para ajudar a criar o recurso dentro do portal do Azure.

Configuração Valor
Grupo de recursos rg-demo
Nome demo-ComputerVision
Sku S1
Localidade eastus

7. Crie um recurso adicional de Visão Computacional

Execute o seguinte comando para criar um recurso da Pesquisa Visual Computacional:

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

8. Obtenha o ponto de extremidade e as chaves do recurso de Visão Computacional

  1. Nos resultados, localize e copie o properties.endpoint. Você precisará disso posteriormente.

    ...
    "properties":{
        ...
        "endpoint": "https://eastus.api.cognitive.microsoft.com/",
        ...
    }
    ...
    
  2. Execute o comando a seguir para obter as chaves.

    az cognitiveservices account keys list \
    --name demo-ComputerVision \
    --resource-group rg-demo
    
  3. Copie uma das chaves; você precisará dela mais tarde.

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

9. Adicione variáveis de ambiente ao seu ambiente local

Para usar o recurso, o código local precisa ter a chave e o ponto de extremidade disponíveis. Essa base de código as armazena em variáveis de ambiente:

  • REACT_APP_AZURE_COMPUTER_VISION_KEY
  • REACT_APP_AZURE_COMPUTER_VISION_ENDPOINT
  1. Execute o comando a seguir para adicionar essas variáveis ao seu ambiente.

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

10. Adicione variáveis de ambiente ao seu ambiente remoto

Ao usar aplicativos Web estáticos do Azure, as variáveis de ambiente, como segredos, precisam ser passadas da ação do GitHub para o aplicativo Web estático. A ação do GitHub cria o aplicativo, incluindo a chave e o ponto de extremidade da Pesquisa Visual Computacional passados dos segredos do GitHub para esse repositório e, em seguida, envia por push o código com as variáveis de ambiente para o aplicativo Web estático.

  1. Em um navegador da Web, no repositório do GitHub, selecione Configurações, Segredos e Novo segredo de repositório.

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

  2. Insira o mesmo nome e valor para o ponto de extremidade usado na seção anterior. Em seguida, crie outro segredo com o mesmo nome e valor para a chave, conforme usado na seção anterior.

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

11. Execute o aplicativo react local com o recurso ComputerVision

  1. Inicie o aplicativo novamente, na linha de comando:

    npm start
    

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

  2. Deixe o campo de texto vazio para selecionar uma imagem do catálogo padrão e selecione o botão Analisar.

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

    A imagem é selecionada aleatoriamente em um catálogo de imagens definido em ./src/DefaultImages.js.

  3. Continue para selecionar o botão Analisar para ver as outras imagens e os resultados.

12. Envie a filial local para o GitHub

No terminal do Visual Studio Code, envie por push o branch local main para o repositório remoto.

git push origin main

Não é preciso fazer commit de alterações porque nenhuma alteração foi executada ainda.

13. Criar um recurso de aplicativo Web estático

  1. Clique no ícone Azure, clique com o botão direito do mouse no serviço Aplicativos Web Estáticos, depois clique em Criar Aplicativo Web Estático (Avançado).

    Visual Studio Code screenshot with Visual Studio extension

  2. Caso uma janela pop-up pergunte se você deseja continuar no branch main, clique em Continuar.

  3. Insira as informações a seguir nos campos subsequentes, apresentados um de cada vez.

    Nome do campo value
    Selecione um grupo de recursos para novos recursos. Selecione o grupo de recursos criado para o recurso ComputerVision: demo-ComputerVision.
    Insira o nome do novo aplicativo Web estático. Demo-ComputerVisionAnalyzer
    Selecionar uma opção de preço Selecione a opção gratuito.
    Selecione o local do código do aplicativo. Escolha a mesma localização selecionada durante a criação do grupo de recursos: eastus.
    Escolha a predefinição de build para configurar a estrutura de projeto padrão. React
    Selecione a localização do código do aplicativo. /
    Insira a localização do código do Azure Functions. Use o valor padrão.
    Insira o caminho da saída do build em relação ao local do seu aplicativo. build

14. Atualize a ação do GitHub com variáveis de ambiente secretas

A chave da Pesquisa Visual Computacional e o ponto de extremidade estão na coleção de segredos do repositório, mas ainda não estão na ação do GitHub. Esta etapa adiciona a chave e o ponto de extremidade à ação.

  1. Puxe as alterações feitas na criação do recurso do Azure para obter o arquivo de ação do GitHub.

    git pull origin main
    
  2. No editor do Visual Studio Code, edite o arquivo de ação do GitHub encontrado em ./.github/workflows/ para adicionar os segredos.

    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. Adicione e confirme a alteração no branch main local.

    git add . && git commit -m "add secrets to action"
    
  4. Envie por push a alteração para o repositório remoto, iniciando uma nova ação build-and-deploy para o aplicativo Web estático do Azure.

    git push origin main
    

15. Veja o processo de compilação da Ação do GitHub

  1. Em um navegador da Web, abra o repositório do GitHub deste tutorial e selecione Ações.

  2. Selecione o primeiro build da lista e, em seguida, selecione Trabalho de Compilar e Implantar no menu do lado esquerdo para ver o processo de build. Aguarde até que Compilar e Implantar seja concluído com êxito.

     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. Exibir site estático remoto do Azure no navegador

  1. No Visual Studio Code, selecione o ícone Azure no menu da extrema direita, selecione seu aplicativo Web estático, clique com o botão direito do mouse em Procurar site e, em seguida, selecione Abrir para exibir o site estático público.

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

Você também pode encontrar a URL para o site nos seguintes locais:

  • no portal do Azure para o recurso, na página Visão geral.
  • na saída do build-and-deploy da ação do GitHub tem a URL do site no final do script

17. Limpar recursos para aplicativo Web estático

Depois de concluir este tutorial, você precisará remover o grupo de recursos, que inclui o recurso da Pesquisa Visual Computacional e o aplicativo Web Estático, para garantir que você não seja cobrado por mais nenhum uso.

No VS Code, selecione o Azure Explorer, clique com o botão direito do mouse no grupo de recursos listado na assinatura e selecione Excluir.

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

Código: Adicionar Visão Computacional ao aplicativo React local

Use npm para adicionar a Pesquisa Visual Computacional ao arquivo package.json.

npm install @azure/cognitiveservices-computervision 

Código: Adicionar código de Visão Computacional como módulo separado

O código da Pesquisa Visual Computacional está contido em um arquivo separado chamado ./src/azure-cognitiveservices-computervision.js. A função principal do módulo é realçada.

// ./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; 
}

Código: Adicionar catálogo de imagens como módulo separado

O aplicativo selecionará uma imagem aleatória de um catálogo se o usuário não inserir uma URL de imagem. A função de seleção aleatória está realçada

// ./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;

Código: Adicionar módulo de Visão Computacional personalizado ao aplicativo React

Adicione métodos ao React app.js. A análise de imagem e a exibição de resultados estão realçadas.

// ./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;

Próximas etapas