静的 Webアプリを構築して Azure にデプロイする
このチュートリアルでは、GitHub アクションを使用して、React/TypeScript クライアント アプリケーションをローカル環境で構築し、Azure Static Web アプリにデプロイします。 React アプリにより、ユーザーは Cognitive Services Computer Vision を使用してイメージを分析できます。
Azure サブスクリプションを作成するか、既存のものを使用する
アクティブなサブスクリプションがある Azure アカウントが必要です。 無料で作成できます。
前提条件
- Node.js および npm - ローカル コンピューターにインストール済み。
- Visual Studio Code - ローカル コンピューターにインストール済み。
- Azure Static Web Apps - React アプリを Azure Static Web Apps にデプロイするために使用されます。
- Git - GitHub にプッシュするために使用されます。これにより GitHub アクションがアクティブになります。
- GitHub アカウント - フォークしてリポジトリにプッシュするため
- Bash 環境で Azure Cloud Shell を使用します。
- 責任ある AI 用語に同意してリソースを作成するには、Azure アカウントに Cognitive Services 共同作成者 ロールが割り当てられている必要があります。 このロールをアカウントに割り当てるには、ロールの割り当てに関するドキュメントの手順に従うか、管理者にお問い合わせください。
Azure Static Web アプリとは
静的 Web アプリを構築する場合、Azure ではユーザーが関心を持つ機能と制御のレベルによって、いくつかの選択肢があります。 このチュートリアルでは、最も簡単なサービスについて重点的に説明します。選択の多くが自動的に行われるため、ユーザーはホスティング環境ではなくフロントエンド コードに集中できます。
React (create-react-app) は次の機能を提供します。
- Cognitive Services Computer Vision の Azure キーとエンドポイントが見つからない場合にメッセージを表示します
- Cognitive Services Computer Vision を使用してイメージを分析できるようにします
- パブリック イメージの URL を入力するか、コレクション内のイメージを分析します
- 分析が完了したとき
- 表示する画像
- Computer Vision JSON の結果を表示する
静的 Web アプリをデプロイするには、特定のブランチへのプッシュ発生時に開始される GitHub アクションを使用します。
- Computer Vision キーとエンドポイントの GitHub シークレットをビルドに挿入します
- React (create-react-app) クライアントを構築します
- 生成されたファイルを Azure 静的 Web アプリ リソースに移動します
1. サンプル リポジトリをフォークする
変更のプッシュ先となる独自の GitHub リポジトリを作成するには、ローカル コンピューターに単純に複製する代わりにリポジトリをフォークします。
別のブラウザー ウィンドウまたはタブを開き、GitHub にサインインします。
GitHub サンプル リポジトリに移動します。
https://github.com/Azure-Samples/js-e2e-client-cognitive-services
ページの右上のセクションで、[Fork]\(フォーク\) を選択します。
[Code]\(コード\) を選択し、フォークの場所の URL をコピーします。
2. ローカル開発環境を作成する
ターミナルまたは bash ウィンドウで、フォークをローカル コンピューターに複製します。
YOUR-ACCOUNT-NAME
を GitHub アカウント名に置き換えます。git clone https://github.com/YOUR-ACCOUNT-NAME/js-e2e-client-cognitive-services
新しいディレクトリに移動し、依存関係をインストールします。
cd js-e2e-client-cognitive-services && npm install
インストール手順では、必要な依存関係 (@azure/cognitiveservices-computervision など) がインストールされます。
3. ローカルのサンプルを実行する
サンプルを実行します。
npm start
アプリを停止します。 ターミナル ウィンドウを閉じるか、ターミナルで
control+c
を使用します。
4. リソース グループを作成する
ターミナルまたは bash シェルで、Azure リソース グループを作成する Azure CLI コマンドを入力して、rg-demo
という名前を指定します。
az group create \
--location eastus \
--name rg-demo \
--subscription YOUR-SUBSCRIPTION-NAME-OR-ID
5. Computer Vision リソースを作成する
リソース グループを作成することにより、リソースを見つけやすくなり、完了時に削除しやすくなります。 この種類のリソースでは、責任ある使用の条件に同意する必要があります。 適切なリソースをすばやく作成する方法については、次の一覧をご覧ください。
- 最初の Computer Vision リソース - 責任ある使用の条件に同意します
- 追加の Computer Vision - 既に責任ある使用の条件に同意しています
6. 最初の Computer Vision リソースを作成する
これが初めての AI サービスの場合は、ポータルでサービスを作成し、そのリソースの作成の一環として、責任ある使用の条件に同意する必要があります。 これが責任ある使用への同意を必要とする最初のリソースではない場合は、次のセクションの Azure CLI を使用してリソースを作成できます。
次の表を使用して、Azure portal 内にリソースを作成してください。
設定 | 値 |
---|---|
リソース グループ | rg-demo |
名前 | demo-ComputerVision |
Sku | S1 |
場所 | eastus |
7. 追加の Computer Vision リソースを作成する
次のコマンドを実行して、Computer Vision リソースを作成します。
az cognitiveservices account create \
--name demo-ComputerVision \
--resource-group rg-demo \
--kind ComputerVision \
--sku S1 \
--location eastus \
--yes
8. Computer Vision リソースのエンドポイントとキーを取得する
その結果から
properties.endpoint
を見つけてコピーします。 この情報は後で必要になります。... "properties":{ ... "endpoint": "https://eastus.api.cognitive.microsoft.com/", ... } ...
次のコマンドを実行して、キーを取得します。
az cognitiveservices account keys list \ --name demo-ComputerVision \ --resource-group rg-demo
キーの 1 つをコピーします。これは後で必要になります。
{ "key1": "8eb7f878bdce4e96b26c89b2b8d05319", "key2": "c2067cea18254bdda71c8ba6428c1e1a" }
9. 環境変数をローカル環境に追加する
リソースを使用するには、ローカル コードでキーとエンドポイントを使用できるようにする必要があります。 このコード ベースは、これらを環境変数に格納します。
- REACT_APP_AZURE_COMPUTER_VISION_KEY
- REACT_APP_AZURE_COMPUTER_VISION_ENDPOINT
次のコマンドを実行して、これらの変数を環境に追加します。
10. 環境変数をリモート環境に追加する
Azure Static Web Apps を使用する場合、シークレットなどの環境変数を GitHub アクションから静的 Web アプリに渡す必要があります。 この GitHub アクションでは、そのリポジトリの GitHub シークレットから渡された Computer Vision キーとエンドポイントを含むアプリがビルドされ、その後、環境変数を含むコードが静的 Web アプリにプッシュされます。
Web ブラウザーの GitHub リポジトリで、[Settings]\(設定\)、[Secrets]\(シークレット\)、[New repository secret]\(新しいリポジトリ シークレット\) を選択します。
エンドポイントに対して前のセクションで使用したものと同じ名前と値を入力します。 次に、前のセクションで使用したものと同じ名前と値のキーを持つ、別のシークレットを作成します。
11. Computer Vision リソースでローカルの React アプリを実行する
コマンドラインで再度アプリを起動します。
npm start
既定のカタログからイメージを選択するために、テキスト フィールドを空のままにして、[Analyze] ボタンを選択します。
イメージは、
./src/DefaultImages.js
で定義されているイメージのカタログからランダムに選択されます。他のイメージと結果を表示するには、[Analyze] ボタンを選択して続行します。
12. ローカル ブランチを GitHub にプッシュする
Visual Studio Code ターミナルで、ローカル ブランチ main
をリモート リポジトリにプッシュます。
git push origin main
変更がまだ行われていないため、変更をコミットする必要はありませんでした。
13. 静的 Web アプリのリソースを作成する
[Azure] アイコンを選択し、[Static Web Apps] サービスを右クリックして、[Create Static Web App (Advanced)]\(静的 Web アプリを作成する (詳細)\) を選択します。
main
分岐に対して続行するかどうかを確認するポップアップウィンドウが表示されたら、[続行] を選択します。次の情報を、一度に 1 つずつ表示される後続のフィールドに入力します。
フィールド名 値 新しいリソース用のリソース グループの選択。 ComputerVision リソース用に作成したリソース グループ demo-ComputerVision
を選択します。新しい静的 Web アプリの名前を入力してください。 Demo-ComputerVisionAnalyzer
価格オプションの選択 [Free] を選択します。 [Select the location of your application code.]\(アプリケーション コードの場所を選択してください。\) リソース グループの作成時に選択したのと同じ場所 ( eastus
) を選択します。既定のプロジェクト構造を構成するためのビルド プリセットの選択。 React
Choose the location of your application code (アプリケーション コードの場所を選択してください)。 /
Enter the location of your Azure Functions code (Azure Functions コードの場所を入力してください)。 既定値を取ります。 [Enter the path of your build output relative to your app's location.]\(アプリの場所を基準とした、ビルド出力のパスを入力します。\) build
14. シークレット環境変数を使用して GitHub アクションを更新する
Computer Vision のキーとエンドポイントは、リポジトリのシークレット コレクションに含まれていますが、まだ GitHub アクションにはありません。 この手順では、キーとエンドポイントをアクションに追加します。
Azure リソースの作成から行った変更をプルし、GitHub アクション ファイルを取得します。
git pull origin main
Visual Studio Code エディターで、
./.github/workflows/
にある GitHub アクション ファイルを編集して、シークレットを追加します。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"
ローカルの
main
ブランチに変更を追加してコミットします。git add . && git commit -m "add secrets to action"
変更をリモート リポジトリにプッシュし、Azure Static Web アプリに対する新しい build and deploy アクションを開始します。
git push origin main
15. GitHub アクションのビルド プロセスを表示する
Web ブラウザーで、このチュートリアル用に GitHub リポジトリを開き、[Actions]\(アクション\) を選択します。
一覧の一番上のビルドを選択し、左側のメニューの [Build and Deploy Job]\(ビルドとデプロイ ジョブ\) を選択してビルド プロセスを監視します。 [Build And Deploy]\(ビルドとデプロイ\) が正常に終了するまで待ちます。
16. ブラウザーでリモートの Azure 静的 Web サイトを表示する
- Visual Studio Code で、右端のメニューの [Azure] アイコンを選択し、静的 Web アプリを選択します。次に [Browse site]\(サイトの参照\) を右クリックし、[Open]\(開く\) を選択して、パブリックな静的 Web サイトを表示します。
サイトの URL は次の場所で見つけることもできます。
- リソースの Azure portal ([Overview]\(概要\) ページ)。
- GitHub アクションの build and deploy 出力には、スクリプトの最後にサイトの URL が含まれています
17. 静的 Web アプリのリソースをクリーンアップする
このチュートリアルを完了したら、Computer Vision リソースおよび静的 Web アプリが含まれているリソース グループを削除し、さらなる使用によって課金されないようにする必要があります。
VS Code で、Azure エクスプローラーを選択し、サブスクリプションの下に一覧表示されているリソース グループを右クリックして、[削除] を選択します。
コード: Computer Vision をローカルの React アプリに追加する
npm を使用して、Computer Vision を package.json ファイルに追加します。
npm install @azure/cognitiveservices-computervision
コード: Computer Vision コードを別のモジュールとして追加する
Computer Vision コードは、./src/azure-cognitiveservices-computervision.js
という名前の別のファイルに含まれています。 このモジュールの主要な関数が強調表示されています。
// ./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;
コード: カスタムの Computer Vision モジュールを 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;