这是我们的一个新系列,好文翻译,会翻译一些看到的技术、趋势类文章,欢迎大家一起来交流,讨论。这篇文章涉及到如何使用Serverless
背景📖
文章的作者Shreya Gupta设定故事背景如下:我们是一群秘密特工,总部告诉我们,我们的一名间谍背叛了我们,并且一直在向敌人泄露敏感的绝密信息。我们的目标是建立一个测谎仪,当我们识别出间谍时,它会提醒我们的间谍网络。我们将使用 Azure 的认知服务对团队中的每个人进行面部识别。当 Face API 识别出我们的间谍之一在欺骗时,我们将使用 Courier 将间谍的身份广播到我们的间谍网络。 查看原文
怎么样?是不是听起来惊险又刺激,下面就拿起我们的技术武器来跟着作者一步一步实现找出间谍吧~
实现🚀
第一步 使用 Azure Functions 创建无服务器应用程序
需要设置本地开发环境启用 Azure 并测试我们的代码
- 在VSCode 里安装以下扩展:
- Azure 工具:用于创建 Azure Functions
- REST 客户端:测试我们的 Azure 函数调用( Postman 或 Insomnia 的替代方案)
成功安装这两个扩展后,检查左侧菜单中是否有 Azure 的 A 符号。如果符号没有自动出现,需要完全关闭并重新打开 VS Code。
构建 HTTP 触发函数:
- 单击 Azure 符号以在本地打开 Azure。在这里,系统会提示我们登录 Azure 帐户
- 登录后,我们需要打开一个 Azure 订阅或创建一个新订阅
如果订阅未在本地显示,不要着急,可以查看这里的指导文档来配置我们的账户~
- 订阅出现后,单击“Workspace”创建一个新项目
- 选择我们需要在这个项目中保存文件的位置以及命名
选择文件位置后,系统会提示我们对要创建的函数类型进行配置
- 选择 JavaScript 作为语言
- 为模板选择 HTTP 触发器
- 将函数重命名为 LieDetector(或其它的唯一名称)
- 为授权级别选择功能
- 打开项目开始编码
让我们打开 index.js 文件,花点时间了解一下样板函数,也可以稍后在 function.json 文件中编辑设置。
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
const name = (req.query.name || (req.body && req.body.name));
const responseMessage = name
? "Hello, " + name + ". This HTTP triggered function executed successfully."
: "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.";
context.res = {
// status: 200, /* Defaults to 200 */
body: responseMessage
};
}
第 4 行演示了我们如何从函数查询或请求正文中获取数据。第 5 行定义了一个responseMessage 字符串变量,该变量使用了第 4 行的数据。在第 9-12 行,此变量被赋值为响应对象response object的context.res。
第二步 授权 Courier 使用 Gmail 和 Twilio API 发送邮件
Courier 通过将多个 API 调用合并为一个来发送消息。在第二部分中,我们需要授权 API 通过 Gmail 和 Twilio API 发送消息。
- 登录到您的 Courier 帐户并创建一个新的秘密工作区。
- 跟随引导流程咱们选择电子邮件并让 Courier 使用 Node.js 构建,设置一般只需几秒钟,我们需要做的就是通过 Gmail 登录,现在 API 已准备好发送消息啦
- 复制启动代码(使用 cURL 进行的基本 API 调用),并将其粘贴到新终端中。它已经保存了您的 API 密钥,知道您要发送到哪个电子邮件地址,并已经设定好了默认消息
一旦你看到特工 Pigeon 跳舞,我们就可以使用 Courier 与我们的间谍进行交流了。在构建应用程序之前,我们需要设置 Twilio 以启用文本消息
- 前往左侧菜单中的“Channels”搜索 Twilio。您将需要一个帐户 SID、身份验证令牌和一个消息服务 SID 来授权 Twilio
- 打开twilio.com,登录并打开控制台,然后在该页面上找到前两个tokens,将 Account SID 和 Auth Token 保存在 Courier 中
最后,我们需要找到左侧菜单的 Messaging 选项卡中创建的 Messaging Service SID。Twilio 的关于如何创建消息服务 SID的文档
一旦我们掌握了所有三个信息,就可以安装provider。我们的 Courier 帐户已获得官方授权,可在一次 API 调用中发送任何电子邮件或 SMS~
第三步 从 Azure 函数发送单通道和多通道通知
我们可以使用 Courier 发送单个消息或设置路由以从 Azure 函数中发送多通道通知。在这一部分中,我们将开始发送消息,大家可以参考 Courier 《Node.js 快速入门》,它概述了如何开始使用 SDK,具体的可以在courier.com的文档页面中学习啦~
如果你更愿意使用 Courier API,可以查看Secret Message 教程来获取说明或Courier 的 API 参考文档。
SDK 文档将引导我们完成对 API 密钥的访问
- 在app.courier.com/settings/ap… 上找到 API 密钥。
- 将 API 密钥保存在 local.settings.json 文件中,并将其引入到index.js文件中,
const apiKey = process.env["API_KEY"]
. 现在可以授权此应用程序使用我们的 Courier 帐户。
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"API_KEY": "replace-with-your-key"
}
}
在终端中运行以下命令来安装 Courier SDK
npm install @trycourier/courier
使用 require 函数将 SDK 导入 index.js 文件
const { CourierClient } = require("@trycourier/courier");
最后一步是遍历 API 文档中的 API 调用并将其集成到我们的代码库中
import { CourierClient } from "@trycourier/courier";
// alternatively:
// const { CourierClient } = require("@trycourier/courier");
const courier = CourierClient({ authorizationToken: "YOUR_AUTH_TOKEN_HERE" });
const { requestId } = await courier.send({
message: {
to: {
email: "email@example.com",
},
content: {
title: "Welcome!",
body: "Thanks for signing up, {{name}}",
},
data: {
name: "Peter Parker",
},
routing: {
method: "single",
channels: ["email"],
},
},
});
- 复制第 5 行并将其粘贴到async函数(Azure 函数)的上方和外部。
- 第 7-24 行中的所有内容都与实际的消息发送有关,需要放在 async 函数中
第 8-23 行的代码定义了消息对象,它向 Courier 提供有关消息的数据:to
对象为接收通知的用户,content
对象为消息包含的内容,data
对象为可能影响content对象的任何变量或者可能影响传出通知的条件,以及routing
对象为正在发送的通知类型。
- 更新要发送消息的电子邮件,为了保护间谍的身份,我们将在此处使用虚假联系信息
- 更新消息。例如,我们可以title将 修改为
Mule Identified
,邮件主题修改为Beware! The mule is {{name}}
, 这样我们就可以硬编码名字或从 HTTP 触发器函数体中获取名字 - 更新
responseMessage
并打印到控制台,这个新的responseMessage
通过从 Courier API 调用输出requestId
响应表明 HTTP 触发的函数运行成功 - 要在本地运行此功能,首先在终端中运行命令
func start
,启用此功能的触发器(以及此项目中的所有功能)。此命令还会返回可用于触发此功能的相应本地的endpoint。
const { requestId } = await courier.send({
message: {
to: {
email: "courier.demos+liedetector@gmail.com",
},
content: {
title: "Mule Identified!",
body: "Beware! The mule's name is {{name}}.",
},
data: {
name: name,
},
routing: {
method: "single",
channels: ["email"],
},
},
});
我们可以使用 Postman 或 Insomnia 来测试这个功能。这里我们使用之前安装的 REST Client VS Code 扩展。
- 创建一个 request.http 文件。
- 要创建新的测试调用,需要在
request.http
文件的顶部键入###
- 定义请求的类型,并将endpoint 粘贴到
POST
的右边。 - 函数调用的主体需要在endpoint下定义。创建一个包含name参数的对象并将其定义为
Secret Agent Pigeon
###
POST http://localhost:7071/api/LieDetector
{
"name": "Secret Agent Pigeon"
}
第4步 用 Face API 分析情绪并使用 Courier 发送警报 Azure 认知服务使我们能够通过 API 和 AI 服务向应用程序添加认知功能(查看提供的所有服务)。在最后一部分中,我们将探索 Azure 认知服务,集成人脸 API 来分析情绪,并使用 Courier API 在检测到特定的欺骗性情绪时发送警报。
- 访问人脸 API,请导航到Azure 门户
- “Create a Resource”并在左侧的类别列表中找到“AI + Machine Learning”
- 从出现的服务列表中选择“Face”,并根据我们的偏好和帐户更新设置
- 点击“Review + Create”,然后点击“Create”开始部署过程(一般需要几分钟才能完成)
- 部署完成后,转到资源,导航到“Keys and Endpoints”下左侧菜单中的“Keys and Endpoints”,复制其中一个密钥和endpoint,并将它们保存在我们项目中 的local.settings.json文件。
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"API_KEY": "replace-with-your-key",
"FACE_API_KEY": "replace-with-your-azure-key",
"FACE_ENDPOINT": "replace-with-your-azure-endpoint"
}
}
这些值为密钥,需要包含在 .gitignore 中
正如我们使用 Courier SDK 一样,我们也需要在 Azure 的 SDK 中使用 Face 服务,该 SDK 可以在Azure Cognitive Services npm 页面上找到。我们将需要在页面上使用这些命令。
npm install @azure/cognitiveservices-face
在终端运行安装人脸服务SDK- 在终端中运行
npm install @azure/ms-rest-azure-js
以安装 REST Azure 客户端 - 从示例代码中复制示例 Face API 调用并将其放入我们的代码库中
- 将import语句移到 Azure 函数上方的顶部
const { FaceClient, FaceModels } = require("@azure/cognitiveservices-face");
const { CognitiveServicesCredentials } = require("@azure/ms-rest-azure-js");
async function main() {
const faceKey = process.env["faceKey"] || "<faceKey>";
const faceEndPoint = process.env["faceEndPoint"] || "<faceEndPoint>";
const cognitiveServiceCredentials = new CognitiveServicesCredentials(faceKey);
const client = new FaceClient(cognitiveServiceCredentials, faceEndPoint);
const url =
"https://pbs.twimg.com/profile_images/3354326900/3a5168f2b45c07d0965098be1a4e3007.jpeg";
const options = {
returnFaceLandmarks: true
};
client.face
.detectWithUrl(url, options)
.then(result => {
console.log("The result is: ");
console.log(result);
})
.catch(err => {
console.log("An error occurred:");
console.error(err);
});
}
main();
现在,我们可以更新代码片段中的变量。
- 将第 43 行的函数名称和第 65 行的相关函数调用更新为analyze_face()
- 修改第 44 行和第 45 行的key names,以匹配我们在 local.settings.json 文件中创建的名称
- 第 49 行包含此 API 将分析的图像。找到指向我们自己图像的链接——为了保护我们间谍的身份,我们将使用 IU 的图像
- 将第 50 行到第 52 行之间的
options
对象更改为returnFaceAttributes
并添加一个数组emotion
作为元素
async function analyze_face() {
const faceKey = process.env["FACE_API_KEY"];
const faceEndPoint = process.env["FACE_ENDPOINT"];
const cognitiveServiceCredentials = new CognitiveServicesCredentials(faceKey);
const client = new FaceClient(cognitiveServiceCredentials, faceEndPoint);
const url =
"https://www.allkpop.com/upload/2021/12/content/231225/web_data/allkpop_1640280755_untitled-1.jpg";
const options = {
returnFaceAttributes: ["emotions"]
};
client.face
.detectWithUrl(url, options)
.then(result => {
console.log("The result is: ");
console.log(result);
})
.catch(err => {
console.log("An error occurred:");
console.error(err);
});
}
analyze_face();
最后,我们需要接收来自这个 API 调用的响应。
- 将响应保存在
result
的变量中 - 使用
stringify
方法将响应转换为 JSON 字符串
const result = await client.face.detectWithUrl(url, options);
const resultJSON = JSON.stringify(result, null, 2);
当我们使用 REST Client 测试我们的功能时,我们遇到了错误: 结果不显示,这意味着由于某种原因,analyze_face()没有返回正确的响应。我们可以查看 Face API 参考来确定错误的原因。我们首先尝试通过从结果对象中删除指定的emotion
来解决问题。
const result = await client.face.detectWithUrl(url, options);
const anger = result[0].faceAttributes.emotion.anger;
const angerJSON = JSON.stringify(anger, null, 2);
实际错误源于第 51 行的误写,其中返回的对象不是复数,应该调用emotion
。当我们测试代码时,我们看到愤怒情绪的值为 0,与所选图像匹配。
const options = {
returnFaceAttributes: ["emotion"]
};
最后,不是返回单个emotion
的值,而是更新analyze_face()
函数以返回整个emotion对象。这将使我们能够比较多种情绪的值,并确定所分析的面部是否具有欺骗性。
const result = await client.face.detectWithUrl(url, options);
return result[0].faceAttributes.emotion;
按照总部的指示,我们知道我们的问题只应引起具体反应,如果一张脸表现出任何愤怒、中立或轻蔑的情绪,我们将不得不假设被质疑的人是间谍。
- 提取这些情绪
const emotions = await analyze_face();
const anger = emotions.anger;
const angerJSON = JSON.stringify(anger, null, 2);
const neutral = emotions.neutral;
const neutralJSON = JSON.stringify(neutral, null, 2);
const contempt = emotions.contempt;
const contemptJSON = JSON.stringify(contempt, null, 2);
用一个简单的条件,将它们与 0 进行比较
if((angerJSON > 0)||(neutralJSON > 0)||(contemptJSON > 0)) {
deceptive = true;
}
如果这些值大于 0,则向我们的整个间谍网络发送警报
const { CourierClient } = require("@trycourier/courier");
const { FaceClient, FaceModels } = require("@azure/cognitiveservices-face");
const { CognitiveServicesCredentials } = require("@azure/ms-rest-azure-js");
const apikey = process.env["API_KEY"];
const courier = CourierClient({ authorizationToken: apikey });
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
const name = (req.query.name || (req.body && req.body.name));
const emotions = await analyze_face();
const anger = emotions.anger;
const angerJSON = JSON.stringify(anger, null, 2);
const neutral = emotions.neutral;
const neutralJSON = JSON.stringify(neutral, null, 2);
const contempt = emotions.contempt;
const contemptJSON = JSON.stringify(contempt, null, 2);
let deceptive = false;
if((angerJSON > 0)||(neutralJSON > 0)||(contemptJSON > 0)) {
deceptive = true;
}
if(deceptive) {
const { requestId } = await courier.send({
message: {
to: {
email: "courier.demos+liedetector@gmail.com",
},
content: {
title: "Mule Identified!",
body: "Beware! The mule's name is {{name}}.",
},
data: {
name: name,
},
routing: {
method: "single",
channels: ["email"],
},
},
});
}
const responseMessage = "The HTTP trigger function ran successfully.";
context.res = {
// status: 200, /* Defaults to 200 */
body: {
responseMessage,
"anger": angerJSON,
"neutral": neutralJSON,
"contempt": contemptJSON
}
};
}
async function analyze_face() {
const faceKey = process.env["FACE_API_KEY"];
const faceEndPoint = process.env["FACE_ENDPOINT"];
const cognitiveServiceCredentials = new CognitiveServicesCredentials(faceKey);
const client = new FaceClient(cognitiveServiceCredentials, faceEndPoint);
const url =
"https://www.allkpop.com/upload/2021/12/content/231225/web_data/allkpop_1640280755_untitled-1.jpg";
const options = {
returnFaceAttributes: ["emotion"]
};
const result = await client.face.detectWithUrl(url, options)
return result[0].faceAttributes.emotion;
}
结论
我们的测谎仪已经准备就绪,只要有俘虏试图惹我们,就会提醒我们的间谍。尝试构建您自己的测谎仪并提醒 courier.demos+liedetector@gmail.com,我们将向前三位特工发送礼物以完成此任务!前往courier.com/hack-now 开始使用。不要忘记将您的项目提交给他们的Hackathon,有机会赢取超过 1000 美元的现金和奖品🏆!有兴趣的小伙伴可以尝试下哦~
最后
如果你对这些WEB前沿技术也有兴趣,欢迎你对我们的文章一键三联,以及关注我们接下来的开源项目————OpenTiny。欢迎微信搜索我们的小助手: opentiny-official
,拉你进群,了解它最新的动态。
Quick Links
🔗 GitHub Repository: github.com/shreythecra…
🔗 Video tutorial: youtu.be/0RJ9m-T7sgU
🔗 Courier: app.courier.com
🔗 Register for the Hackathon: courier-hacks.devpost.com/
🔗 Courier's Get Started with Node.js: www.courier.com/docs/guides…
🔗 Courier Send API Docs: www.courier.com/docs/refere…
🔗 Twilio Messaging Service SID Docs: support.twilio.com/hc/en-us/ar…
🔗 Courier API Reference: www.courier.com/docs/refere…
🔗 Azure for Students: azure.microsoft.com/en-us/free/…
🔗 Troubleshooting Azure Account Setup: github.com/microsoft/v…
🔗 Azure Cognitive Services: azure.microsoft.com/en-us/servi…
🔗 Azure Portal: portal.azure.com/
🔗 Azure Cognitive Services SDK: www.npmjs.com/package/@az…