練習 - 使用 Azure Functions 中撰寫函數應用程式以分析相片

已完成

在本單元中,您將使用 Azure Functions 撰寫一種應用程式,只要有影像上傳至儲存體帳戶的 photos 容器,就會觸發此應用程式。 此函數應用程式會使用所建立的自訂視覺模型來判斷相片中是否有北極熊。

在 Azure 中建立函數應用程式

您可在 Azure 入口網站中使用 Azure Functions,或從外部使用 Visual Studio 之類的工具來撰寫函數應用程式。 在此練習中,您將在入口網站中撰寫函數應用程式。 您將使用 JavaScript 撰寫函數應用程式,並透過使用 Azure Functions 的 Node.js 執行階段執行函數應用程式。 每次將影像上傳至您在 Blob 儲存體中建立的 photos 容器時,就會觸發函數應用程式。 然後,函數應用程式會將上傳的每個 Blob 傳遞至至自訂視覺,以分析是否有北極熊。

  1. 在瀏覽器中,返回 Azure 入口網站。 在 [Azure 服務] 中,選取 [建立資源]。 在資源功能表中,依序選取 [計算] 和 [函數應用程式]

    Screenshot that shows numbered elements in the Azure portal that you select to create a new function app resource.

    在 Azure 中建立新的函數應用程式

  2. 在 [建立函數應用程式] 的 [基本資訊] 索引標籤上,輸入或選取下列值:

    • 訂用帳戶:選取您需要使用的訂用帳戶。
    • 資源群組:選取 polar-bear-rg
    • 函數應用程式名稱:針對新的應用程式,輸入 Azure 中的唯一名稱。
    • 發佈:將 [程式碼] 保持為選取狀態。
    • 執行階段堆疊:選取 [Node.js]。
    • 區域:選取 [美國中南部]。
    • 作業系統:選取您的系統。
    • 方案類型:選取 [使用量 (無伺服器)]。
    • 選取 [下一步:裝載]

    Screenshot that shows the basic settings to select or enter for a new function app.

    設定新函數應用程式的基本設定

  3. 在 [主機] 索引標籤上,選取您建立用於上傳野生動物相片的儲存體帳戶。 然後,選取 [檢閱 + 建立]

    Screenshot that shows the hosting tab settings for a new function app.

    設定新函數應用程式的主機設定

  4. 等待驗證完成,然後選取 [建立]

  5. 等待函數應用程式部署,然後在 Azure 入口網站中開啟該應用程式。 在資源功能表的 [函數] 下,依序選取 [函數] 和 [建立]

    Screenshot that highlights the elements to select to add a function in the Azure portal.

    新增函式

  6. 在 [新增函式] 中:

    1. 針對 [開發環境],選取 [在入口網站中開發]
    2. 在 [範本] 底下,選取 [Azure Blob 儲存體觸發程序]

    Screenshot that highlights the elements to select for a new function.

    進行設定並選擇函數的範本

    注意

    如果系統提示您安裝 Microsoft.Azure.WebJobs.Extensions.Storage 延伸模組,請選取 [安裝]

    等待安裝完成,然後選取 [繼續]

    (如果系統「未」提示您安裝延伸模組,則可能必須等候幾分鐘,才能繼續進行下一個步驟。)

  7. 在 [範本詳細資料] 中:

    1. 針對 [新增函數] 輸入 BlobTrigger

    2. 針對 [路徑] 輸入 photos/{名稱},讓函數應用程式在 Blob 上傳至 photos 容器時觸發。

    3. 在 [儲存體帳戶連線] 底下,選取 [新增]

      注意

      複製並儲存 [儲存體帳戶連線] 中顯示的值。 您將在稍後的步驟中使用此值。

    4. 在 [新增儲存體帳戶連線] 中,選取您稍早建立的儲存體帳戶,然後選取 [確定]

    Screenshot that shows settings to use to set up the template to create a blob-triggered function.

    設定範本以建立 Blob 觸發函式

  8. 選取新增。 入口網站檢視會變更以顯示新的應用程式。

  9. 在新觸發程序函數的 [概觀] 頁面上,於 [開發人員] 底下,選取 [編碼 + 測試]。 觸發程序的 index.js 檔案會在入口網站中開啟。

    Screenshot that highlights the portal elements to select to open the index dot J S file for the blob-triggered function.

    開啟觸發程序函式的 index.js 檔案

  10. 複製下列程式碼,並以該程式碼取代 Azure 入口網站中的函數應用程式程式碼:

    module.exports = function (context, myBlob) {
        var predictionUrl = process.env.PREDICTION_URL;
        var predictionKey = process.env.PREDICTION_KEY;
        var storageConnectionString = process.env.<CONNECTION_STRING_NAME>;
    
        var storage = require('azure-storage');
        var blobService = storage.createBlobService(storageConnectionString);
        var blobName = context.bindingData.name;
        var blobUri = context.bindingData.uri;
    
        // Read the blob's metadata
        blobService.getBlobMetadata('photos', blobName, (err, result, response) => {
            if (!err) {
                var latitude = result.metadata.latitude;
                var longitude = result.metadata.longitude;
                var id = result.metadata.id;
    
                // Generate a shared access signature for the Custom Vision service
                var now = new Date();
                var expiry = new Date(now).setMinutes(now.getMinutes() + 3);
    
                var policy = {
                    AccessPolicy: {
                        Permissions: storage.BlobUtilities.SharedAccessPermissions.READ,
                        Start: now,
                        Expiry: expiry
                    },
                };
    
                var sas = blobService.generateSharedAccessSignature('photos', blobName, policy);
    
                // Pass the blob URL to the Custom Vision service
                var request = require('request');
    
                var options = {
                    url: predictionUrl,
                    method: 'POST',
                    headers: {
                        'Prediction-Key': predictionKey
                    },
                    body: {
                        'Url': blobUri + '?' + sas
                    },
                    json: true
                };
    
                request(options, (err, result, body) => {
                    if (!err) {
                        var probability =  body.predictions.find(p => p.tagName.toLowerCase() === 'polar-bear').probability;
                        var isPolarBear = probability > 0.8; // 80% threshold
                         if (isPolarBear) {
                            context.log('POLAR BEAR detected by ' + id + ' at ' + latitude + ', ' + longitude);
                        }
                        else {
                            context.log('Other wildlife detected by ' + id + ' at ' + latitude + ', ' + longitude);
                        }
    
                        context.done();
                    }
                    else {
                        context.log(err);
                        context.done();
                    }
                });
            }
            else {
                context.log(err);
                context.done();
            }
        });
    };
    

    所修改函數應用程式會使用 npm request 模組呼叫自訂視覺服務,並傳遞要分析的影像 URL。 其會剖析 JSON 結果並擷取值,指出影像包含北極熊的機率。 然後會將結果寫入輸出記錄。 判斷影像是否包含北極熊的閾值是 80%:

    var isPolarBear = probability > 0.8; // 80% threshold
    

    此程式碼另一個值得注意的層面是使用共用存取簽章

    您所建立的 photos 容器屬私人性質。 若要存取儲存在此的 Blob,則必須有儲存體帳戶的存取權,或有儲存體帳戶的存取金鑰。 共用存取簽章允許其他使用者和服務存取個別的 Blob,但有時間長度限制和選擇性唯讀存取權。

    您貼入入口網站的程式碼會使用適用於 Node.js 的 Azure 儲存體 SDK (azure-storage),針對與 URL (傳遞至自訂視覺) 建立關聯的 Blob 產生唯讀的共用存取簽章。 此程式碼會將共用存取簽章附加至 Blob URL 作為查詢字串。 共用存取簽章的有效時間為 3 分鐘,且僅允許讀取權限。 您的程式碼可將私人 Blob 提交給自訂視覺進行分析,而不用將 Blob 放在任何人都可以在其中進行下載的公用容器內。

  11. 以您稍早儲存的儲存體帳戶連接字串 (例如,polarbearstorage_STORAGE) 取代第 4 行上的 <CONNECTION_STRING_NAME>。 當將 BlobTrigger 函數新增至函數應用程式時,就會將此連接字串新增至應用程式設定。 其名稱衍生自儲存體帳戶名稱。 如有需要,您可以在函數應用程式的 [應用程式設定] 中查詢儲存體帳戶的連接字串。

    新增儲存體帳戶的連接字串之後,請選取 [儲存],完成對 index.js 檔案進行的變更。 儲存檔案時,函數的輸出記錄會在頁面的底部開啟。

  12. 在 Azure 入口網站中開啟主控台。

    • 在函數應用程式的 [概觀] 頁面上,於資源功能表的 [開發工具] 底下,選取 [主控台]

    Screenshot that shows how to open a console for a function app.

    開啟函數應用程式主控台

  13. 在主控台中,執行下列命令以安裝 npm request 套件和適用於 Node.js 的 Azure 儲存體 SDK,讓您的函數應用程式可以使用這兩者。

    npm install request
    npm install azure-storage
    

    注意

    請忽略所顯示的任何警告訊息。 為了簡單起見,我們將使用舊版 JavaScript 程式庫。

  14. 等候安裝命令完成。 然後,您會將兩個應用程式設定新增至函數應用程式。

    1. 在資源功能表的 [設定] 底下,選取 [組態]
    2. 在 [應用程式設定] 中,選取 [新增應用程式設定]
    3. 在 [新增/編輯應用程式設定] 中,新增名為 PREDICTION_URL 的設定。 將值設定為您在上一個單元中儲存的自訂視覺預測 URL。 將 [部署位置設定] 保持為清除狀態。 選取 [確定]。
    4. 重複上述步驟,以新增名為 PREDICTION_KEY 的設定。 將值設定為您在上一個單元中儲存的自訂視覺預測金鑰。 將 [部署位置] 設定保持為清除狀態。 選取 [確定]。

    Screenshot that shows selections to make in the Azure portal for application settings for a function app.

    設定函數應用程式的應用程式設定

    請選取 [儲存] 完成此作業。 如果出現提示,請選取 [繼續] 完成儲存動作。

    注意

    您不會在函數應用程式的程式碼中將自訂視覺 URL 和驗證金鑰進行硬式編碼,而是將這些值儲存在函數應用程式的應用程式設定中。 這些值儲存在應用程式設定時會更安全。

  15. 若要回到 BlobTrigger 函數應用程式,請在資源功能表的 [函數] 下,依序選取 [函數] 和 [BlobTrigger]

    Screenshot that shows selections to make in the Azure portal to view the blob trigger function app.

    開啟 BlobTrigger 函數應用程式

  16. 在資源功能表的 [開發人員] 下,選取 [編碼 + 測試]。 在所顯示的程式碼下方,選取 [記錄] 向上箭號。 記錄輸出窗格隨即開啟。

    Screenshot that shows how to open the output log for a function.

    開啟函數的輸出記錄

    將 [記錄] 窗格保持為開啟狀態,因為我們會在稍後的步驟中使用該窗格。

  17. 若要開啟 photos Blob 儲存體容器,請在資源功能表的 [資料儲存體] 下,選取 [容器]。 在容器清單中選取 photos 容器。

    Screenshot that highlights the items you select in the Azure portal to open the photos container.

    開啟 Blob 儲存體帳戶的 photos 容器

  18. 接下來,將影像上傳至 photos 容器,以試用您的函數應用程式。

    1. photos 容器窗格中,選取 [上傳]
    2. 在 [上傳 Blob] 的 [檔案] 下,選取資料夾圖示。
    3. 在 Windows 檔案總管中,移至專案目錄中的 photos 資料夾。
    4. 選取 image_12.jpg 檔案,然後選取 [開啟]
    5. 在 [上傳 Blob] 中,選取 [上傳]。 上傳完成後,請選取 [X] 以關閉窗格。

    Screenshot that shows how to upload a photo to a container.

    將相片上傳至容器

    以下是 image_12.jpg 看起來的樣子:

    Image 12 dot j p g, which shows a polar bear.

    Blob 儲存體中的 image_12

  19. 在瀏覽器中返回函數應用程式記錄。 確認函數應用程式已執行,而且自訂視覺指出 image_12.jpg 包含北極熊。

    Screenshot that shows the output log details for uploading and analyzing image 12 dot j p g.

    檢視上傳和分析 image_12 的輸出記錄詳細資料

在記錄輸出中出現 undefined at undefined, undefined 文字的原因是,函數嘗試從 Blob 中繼資料讀取緯度、經度和相機識別碼,並將其包含在輸出中。 但由於您手動上傳此 Blob,因此這些中繼資料值並不存在。 當虛擬相機將相片上傳至 Blob 儲存體時,該狀況就會變更。

執行相機陣列

接下來,執行您稍早建立的模擬相機陣列。 然後,您將檢查此函數應用程式的記錄輸出,以確認影像會上傳至 Blob 儲存體並分析是否有北極熊。

  1. 在命令提示字元或終端機視窗中,返回專案目錄。 執行下列程式碼以執行 run.js

    node run.js
    
  2. 在 Azure 入口網站中,返回 BlobTrigger 函數,並監看輸出記錄一到兩分鐘。 確認函數會觸發並呼叫自訂視覺,以判斷每個上傳至 photos 容器的相片是否包含北極熊。

    Screenshot that shows logs in a terminal, with the log entry Polar Bear detected for one of the cameras and the camera's latitude and longitude.

    有北極熊!

  3. 返回正在執行 run.js 的命令提示字元或終端機視窗,並選取 Ctrl+C。

恭喜! 您已建置一套系統,可將野生動物相片傳輸至 Blob 儲存體,並使用 Azure AI 自訂視覺模型判斷哪些相片包含北極熊。 下一個步驟是讓輸出更具視覺效果,而這會從使用 Azure SQL Database 建立 SQL 資料庫開始著手。