在本教程中,你将了解如何将图像上传到 Azure Blob 存储并使用 Azure Functions、计算机视觉和 Cosmos DB 对其进行处理。 你还将了解如何在此过程中实现 Azure Function 触发器和绑定。 这些服务将一起分析包含文本的上传图像,从中提取文本,然后将文本存储在数据库行中,供以后分析或用于其他用途。
Azure Blob 存储是 Azure 针对云提供的可大规模缩放的对象存储解决方案。 Blob 存储设计用于存储图像和文档、流式处理媒体文件、管理备份和存档数据等等。 有关 Blob 存储的详细信息,请阅读概述页面。
警告
本教程旨在快速采用,因此它不遵循默认安全要求。 若要详细了解此方案并采用默认安全目标,请前往安全注意事项。
Azure Cosmos DB 是一种用于新式应用开发的完全托管的 NoSQL 数据库和关系数据库。
Azure Functions 是一种无服务器计算机解决方案,允许你编写和运行小块代码作为高度可缩放、无服务器、事件驱动的函数。 有关 Azure Functions 的详细信息,请阅读概述页面。
本教程介绍如何执行下列操作:
- 将图像和文件上传到 Blob 存储
- 使用 Azure Function 事件触发器处理上传到 Blob 存储的数据
- 使用 Azure AI 服务分析图像
- 使用 Azure Function 输出绑定将数据写入 Cosmos DB
              
               
              
              
            
先决条件
- 具有活动订阅的 Azure 帐户。 创建试用帐户。
- 已安装 Visual Studio Code。
- Azure Functions 扩展,用于部署和配置函数应用。
- Azure 存储扩展
- Azure 数据扩展插件
- Azure 资源扩展
 
创建存储帐户和容器
第一步是创建存储帐户来保存上传的 blob 数据,在本方案中为包含文本的图像。 存储帐户可提供多种不同的服务,但本教程仅使用了 Blob 存储。
- 在 Visual Studio Code 中,选择 Ctrl + Shift + P 以打开命令面板。 
- 搜索“Azure 存储: 创建存储帐户(高级)”。 
- 使用下表创建存储资源。 - 设置 - 值 - 名称 - 输入“msdocsstoragefunction”或类似内容。 - 资源组 - 创建你之前创建的 - msdocs-storage-function资源组。- 静态 Web 托管 - 否。 
- 在 Visual Studio Code 中,选择 Shift + Alt + A 以打开 Azure 资源管理器。 
- 展开“存储”部分,展开订阅节点并等待创建资源。 
在 Visual Studio Code 中创建容器
- 仍在 Azure 资源浏览器中,找到新的存储资源,展开资源以查看节点。
- 右键单击“Blob 容器”,然后选择“创建 Blob 容器”。
- 输入名称 images。 这将创建一个专用容器。
在 Azure 门户中从专用容器更改为公共容器
此过程需要一个公共容器。 若要更改该配置,请在 Azure 门户中进行更改。
- 右键单击 Azure 资源管理器中的存储资源,选择“在门户中打开”。
- 在“数据存储”部分,选择“容器”。
- 找到容器 images,然后选择行尾的...(省略号)。
- 选择“更改访问级别”。
- 选择“Blob (仅匿名读取访问 blob)”,然后选择“确定”。
- 返回到 Visual Studio Code。
在 Visual Studio Code 中检索连接字符串
- 在 Visual Studio Code 中,选择 Shift + Alt + A 以打开 Azure 资源管理器。
- 右键单击存储资源,然后选择“复制连接字符串”。
- 将该内容粘贴到某处供稍后使用。
- 记下存储帐户的名称 msdocsstoragefunction供稍后使用。
创建 Azure AI 视觉服务
接下来,创建 Azure AI 视觉服务帐户来处理上传的文件。 视觉是 Azure AI 服务的一部分,可提供各种用于从图像中提取数据的功能。 有关 Azure AI 视觉的详细信息,请阅读概述页面。
- 在门户顶部的搜索栏中,搜索“计算机”并选择标有“计算机视觉”的结果。 
- 在“计算机视觉”页面上,选择“+ 创建”。 
- 在“创建计算机视觉”页面上,输入以下值: - 订阅:选择所需的订阅。
- 
              资源组:使用之前创建的 msdocs-storage-function资源组。
- 区域:选择离你最近的区域。
- 
              名称:输入名称 msdocscomputervision。
- 定价层:如果可用,请选择“免费”,否则选择“标准 S1”。
- 选中“负责任的 AI 声明”框(如果同意这些条款)
 
- 选择底部的“查看 + 创建”。 Azure 需要花点时间来验证你输入的信息。 验证设置后,选择“创建”,Azure 将开始预配计算机视觉服务,这可能需要一些时间。 
- 操作完成后,选择“转到资源”。 
检索计算机视觉键
接下来,我们需要找到计算机视觉服务的密钥和终结点 URL,以在 Azure Function App 中使用。
- 在“计算机视觉”概述页面上,选择“密钥和终结点”。 
- 在“键和终结点”页面上,复制“键 1”的值和“终结点”的值,并将它们粘贴到某处供稍后使用。 终结点的格式应为 - https://YOUR-RESOURCE-NAME.cognitiveservices.azure.cn/
              
               
              
              
            
创建 Cosmos DB 服务帐户
创建 Cosmos DB 服务帐户来存储文件分析结果。 Azure Cosmos DB 是一种用于新式应用开发的完全托管的 NoSQL 数据库和关系数据库。 你可以详细了解 Cosmos DB 及其针对多个不同行业数据库的支持 API。
虽然本教程在创建资源时指定了一个 API,但 Cosmos DB 的 Azure 函数绑定的配置方式与所有 Cosmos DB API 相同。
- 在门户顶部的搜索栏中,搜索“Azure Cosmos DB”并选择相应结果。 
- 在“Azure Cosmos DB”页面上,选择“+ 创建”。 从 API 选项列表中选择“Azure Cosmos DB for NoSQL”。 
- 在“创建 Cosmos DB”页面上,输入以下值: - 订阅:选择所需的订阅。
- 
              资源组:使用之前创建的 msdocs-storage-function资源组。
- 区域:选择你的资源组所在的同一区域。
- 
              名称:输入名称 msdocscosmosdb。
- 定价层:如果可用,请选择“免费”,否则选择“标准 S1”。
 
- 选择底部的“查看 + 创建”。 Azure 会花点时间验证输入的信息。 验证设置后,选择“创建”,Azure 将开始预配计算机视觉服务,这可能需要一些时间。 
- 操作完成后,选择“转到资源”。 
- 依次选择“数据资源管理器”和“新建容器”。 
- 使用以下设置创建新数据库和容器: - 创建新数据库 ID:StorageTutorial。
- 输入新的容器 ID:analysis。
- 输入分区键:/type。
 
- 创建新数据库 ID:
- 保留其余默认设置,并选择“确定”。 
获取 Cosmos DB 连接字符串
获取 Cosmos DB 服务帐户的连接字符串,以便在 Azure 函数应用中使用。
- 在“Cosmos DB”概述页面上,选择“键”。 
- 在“键”页面上,复制主连接字符串以供稍后使用。 
下载并配置示例项目
本教程中使用的 Azure 函数的代码可在此 GitHub 存储库的 JavaScript-v4 子目录中找到。 也可以使用以下命令克隆项目。
git clone https://github.com/Azure-Samples/msdocs-storage-bind-function-service.git \
cd msdocs-storage-bind-function-service/javascript-v4 \
code .
示例项目将完成以下任务:
- 检索环境变量以连接到存储帐户、计算机视觉和 Cosmos DB 服务
- 接受上传的文件作为 blob 参数
- 使用计算机视觉服务分析 blob
- 使用输出绑定将分析的图像文本作为 JSON 对象插入 Cosmos DB 中
下载并打开项目后,需要了解一些基本概念:
| 概念 | 目的 | 
|---|---|
| 函数 | Azure 函数由函数代码和绑定定义。 它们位于 ./src/functions/process-blobs.js 中。 | 
| 触发器和绑定 | 触发器和绑定指示预期传入或传出函数的数据,以及要发送或接收该数据的服务。 | 
本教程中使用的触发器和绑定无需编写代码即可连接到服务,可加快开发过程。
存储 Blob 输入触发器
下面的代码指定了在有 Blob 上传到图像容器时触发相应的函数。 该函数可在任何 Blob 名称(包括分层文件夹)上触发。
// ...preceding code removed for brevity
app.storageBlob('process-blob-image', { 
    path: 'images/{name}',                // Storage container name: images, Blob name: {name}
    connection: 'StorageConnection',      // Storage account connection string
    handler: async (blob, context) => {
// ... function code removed for brevity
- app.storageBlob - 存储 Blob 输入触发器用于将函数绑定到 Blob 存储中的上传事件。 触发器具有两个必需参数:- 
              path:触发器监视事件的路径。 该路径包括容器名称images以及 blob 名称的变量替换。 此 blob 名称是从name属性中检索的。
- 
              {name}:已上传的 blob 的名称。blob的使用是传入函数的 blob 的参数名称。 请勿更改值blob。
- 
              connection:存储帐户的连接字符串。 在本地开发时,值StorageConnection与local.settings.json文件中的名称相匹配。
 
- 
              
Cosmos DB 输出触发器
完成相应函数后,该函数会将返回的对象作为数据插入到 Cosmos DB 中。
// ... function definition object
app.storageBlob('process-blob-image', { 
    
        // removed for brevity    
        
        // Data to insert into Cosmos DB
        const id = uuidv4().toString();
        const analysis = await analyzeImage(blobUrl);
        
        // `type` is the partition key 
        const dataToInsertToDatabase = {
                id,
                type: 'image',
                blobUrl,
                blobSize: blob.length,
                analysis,
                trigger: context.triggerMetadata
            }
        return dataToInsertToDatabase;
    }),
    // Output binding for Cosmos DB
    return: output.cosmosDB({
        connection: 'CosmosDBConnection',
        databaseName:'StorageTutorial',
        containerName:'analysis'
    })
});
对于本文中的容器,以下是必需的属性:
- id:Cosmos DB 创建新行所需的 ID。
- /type:创建容器时指定的分区键。
- output.cosmosDB - Cosmos DB 输出触发器用于将函数的结果插入到 Cosmos DB 中。 - 
              connection:存储帐户的连接字符串。 值StorageConnection与local.settings.json文件中的名称匹配。
- 
              databaseName:要连接到的 Cosmos DB 数据库。
- 
              containerName:写入函数返回的已分析图像文本值的表的名称。 该表必须已存在。
 
- 
              
Azure 函数代码
下面是完整的函数代码。
const { app, input, output } = require('@azure/functions');
const { v4: uuidv4 } = require('uuid');
const { ApiKeyCredentials } = require('@azure/ms-rest-js');
const { ComputerVisionClient } = require('@azure/cognitiveservices-computervision');
const sleep = require('util').promisify(setTimeout);
const STATUS_SUCCEEDED = "succeeded";
const STATUS_FAILED = "failed"
const imageExtensions = ["jpg", "jpeg", "png", "bmp", "gif", "tiff"];
async function analyzeImage(url) {
    try {
        const computerVision_ResourceKey = process.env.ComputerVisionKey;
        const computerVision_Endpoint = process.env.ComputerVisionEndPoint;
        const computerVisionClient = new ComputerVisionClient(
            new ApiKeyCredentials({ inHeader: { 'Ocp-Apim-Subscription-Key': computerVision_ResourceKey } }), computerVision_Endpoint);
        const contents = await computerVisionClient.analyzeImage(url, {
            visualFeatures: ['ImageType', 'Categories', 'Tags', 'Description', 'Objects', 'Adult', 'Faces']
        });
        return contents;
    } catch (err) {
        console.log(err);
    }
}
app.storageBlob('process-blob-image', { 
    path: 'images/{name}',
    connection: 'StorageConnection',
    handler: async (blob, context) => {
        context.log(`Storage blob 'process-blob-image' url:${context.triggerMetadata.uri}, size:${blob.length} bytes`);
        const blobUrl = context.triggerMetadata.uri;
        const extension = blobUrl.split('.').pop();
        if(!blobUrl) {
            // url is empty
            return;
        } else if (!extension || !imageExtensions.includes(extension.toLowerCase())){
            // not processing file because it isn't a valid and accepted image extension
            return;
        } else {
            //url is image
            const id = uuidv4().toString();
            const analysis = await analyzeImage(blobUrl);
            
            // `type` is the partition key 
            const dataToInsertToDatabase = {
                    id,
                    type: 'image',
                    blobUrl,
                    blobSize: blob.length,
                    ...analysis,
                    trigger: context.triggerMetadata
                }
            return dataToInsertToDatabase;
        }
        
    },
    return: output.cosmosDB({
        connection: 'CosmosDBConnection',
        databaseName:'StorageTutorial',
        containerName:'analysis'
    })
});
此代码还从环境变量中检索基本配置值,例如 Blob 存储连接字符串和计算机视觉密钥。 这些环境变量在部署后添加到 Azure 函数环境。
默认函数还会使用名为 AnalyzeImage 的第二种方法。 此代码使用计算机视觉帐户的 URL 终结点和密钥向计算机视觉发出处理图像的请求。  该请求返回图像中发现的所有文本。 此文本将使用出站绑定写入 Cosmos DB。
配置本地设置
若要在本地运行项目,请在 ./local.settings.json 文件中输入环境变量。 使用之前在创建 Azure 资源时保存的值填充占位符值。
尽管 Azure 函数代码在本地运行,但它将连接到基于云的存储服务,而不是使用任何本地模拟器。
{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "AzureWebJobsStorage": "",
    "StorageConnection": "STORAGE-CONNECTION-STRING",
    "StorageAccountName": "STORAGE-ACCOUNT-NAME",
    "StorageContainerName": "STORAGE-CONTAINER-NAME",
    "ComputerVisionKey": "COMPUTER-VISION-KEY",
    "ComputerVisionEndPoint":  "COMPUTER-VISION-ENDPOINT",
    "CosmosDBConnection": "COSMOS-DB-CONNECTION-STRING"
  }
}
创建 Azure Functions 应用
现在可以使用 Visual Studio Code 扩展将应用程序部署到 Azure。
- 在 Visual Studio Code 中,选择 Shift + Alt + A 以打开 Azure 资源管理器。 
- 在“Functions”部分,找到并右键单击订阅,然后选择“在 Azure 中创建函数应用(高级)”。 
- 使用下表创建函数资源。 - 设置 - 值 - 名称 - 输入 msdocsprocessimage 或类似内容。 - 运行时堆栈 - 选择一个 Node.js LTS 版本。 - 编程模型 - 选择“v4”。 - OS - 选择“Linux”。 - 资源组 - 选择之前创建的 - msdocs-storage-function资源组。- 位置 - 选择你的资源组所在的同一区域。 - 计划类型 - 选择“消耗”。 - Azure 存储 - 选择前面创建的存储帐户。 - Application Insights - 暂时跳过。 
- Azure 将预配请求的资源,这需要一些时间才能完成。 
部署 Azure Functions 应用
- 上一个资源创建过程完成后,在 Azure 资源管理器的“Functions”部分中右键单击新资源,然后选择“部署到函数应用”。
- 如果系统询问“是否确定要部署...”,请选择“部署”。
- 该过程完成后,会显示一条通知,其中包含“上传设置”的选项。 选择该选项。 这会将值从 local.settings.json 文件复制到 Azure 函数应用中。 如果通知在你进行选择之前就消失了,请继续执行下一部分。
为存储和计算机视觉添加应用设置
如果在通知中选择了“上传设置”,请跳过此部分。
Azure 函数已成功部署,但它还无法连接到存储帐户和计算机视觉服务。 必须先将正确的密钥和连接字符串添加到 Azure Functions 应用的配置设置。
- 在 Azure 资源管理器的“Functions”部分,查找你的资源,右键单击“应用程序设置”,然后选择“添加新设置”。 
- 为以下机密输入新的应用设置。 将机密值从本地项目复制并粘贴到 - local.settings.json文件中。- 设置 - StorageConnection - StorageAccountName - StorageContainerName - ComputerVisionKey - ComputerVisionEndPoint - CosmosDBConnection 
将 Azure Function 连接到不同服务所需的所有环境变量现已到位。
将图像上传到 Blob 存储
现在可以测试应用程序了! 你可以将 blob 上传到容器,然后验证图像中的文本是否已保存到 Cosmos DB。
- 在 Visual Studio Code 的 Azure 资源管理器中,在“存储”部分查找并展开你的存储资源。
- 展开“Blob 容器”,右键单击容器名称 images,然后选择“上传文件”。
- 你可以在可下载示例项目的根目录的 images 文件夹中找到一些示例图像,也可以使用自己的图像。
- 对于“目标目录”,接受默认值 /。
- 等待文件上传并列在容器中。
查看图片的文本分析
接下来,可以验证上传是否触发了 Azure 函数,以及图像中的文本是否已正确分析并保存到 Cosmos DB 中。
- 在 Visual Studio Code 中,在 Azure 资源管理器的 Azure Cosmos DB 节点下,选择资源,然后展开该资源以查找数据库“StorageTutorial”。 
- 展开数据库节点。 
- 分析容器现已应该可用。 选择容器的“文档”节点,以预览其中的数据。 你应会看到已上传文件的已处理图像文本的条目。 - { "id": "3cf7d6f0-a362-421e-9482-3020d7d1e689", "type": "image", "blobUrl": "https://msdocsstoragefunction.blob.core.chinacloudapi.cn/images/presentation.png", "blobSize": 1383614, "analysis": { ... details removed for brevity ... "categories": [], "adult": {}, "imageType": {}, "tags": [], "description": {}, "faces": [], "objects": [], "requestId": "eead3d60-9905-499c-99c5-23d084d9cac2", "metadata": {}, "modelVersion": "2021-05-01" }, "trigger": { "blobTrigger": "images/presentation.png", "uri": "https://msdocsstorageaccount.blob.core.chinacloudapi.cn/images/presentation.png", "properties": { "lastModified": "2023-07-07T15:32:38+00:00", "createdOn": "2023-07-07T15:32:38+00:00", "metadata": {}, ... removed for brevity ... "contentLength": 1383614, "contentType": "image/png", "accessTier": "Hot", "accessTierInferred": true, }, "metadata": {}, "name": "presentation.png" }, "_rid": "YN1FAKcZojEFAAAAAAAAAA==", "_self": "dbs/YN1FAA==/colls/YN1FAKcZojE=/docs/YN1FAKcZojEFAAAAAAAAAA==/", "_etag": "\"7d00f2d3-0000-0700-0000-64a830210000\"", "_attachments": "attachments/", "_ts": 1688743969 }
恭喜! 你已成功使用 Azure Functions 和计算机视觉处理上传到 Blob 存储的图像。
疑难解答
请使用下表帮助解决此过程中的问题。
| 问题 | 解决方法 | 
|---|---|
| await computerVisionClient.read(url);出现错误Only absolute URLs are supported | 请确保 ComputerVisionEndPoint终结点采用https://YOUR-RESOURCE-NAME.cognitiveservices.azure.cn/格式。 | 
安全注意事项
作为初学者教程,此解决方案没有演示默认情况下的安全做法。 这是为了使你能够成功部署解决方案。 成功部署后的下一步是保护资源。 此解决方案使用三个 Azure 服务,每个服务都有自己的安全功能和安全默认配置注意事项:
- Azure Functions - 保护 Azure Functions
- Azure Storage - 有关 Blob 存储的安全性建议
- Azure 认知服务 -Azure AI 服务安全功能
代码示例
清理资源
如果不打算继续使用此应用程序,可以通过删除资源组来删除创建的资源。
- 从 Azure 资源管理器中选择“资源组”
- 从列表中找到并右键单击 msdocs-storage-function资源组。
- 选择“删除”。 删除资源组的过程可能需要几分钟才能完成。
 
              
               
              
               
              
              