介绍
Easegress 是 MegaEase 开发的新一代流量型网关产品,它完全架构于云原生技术之上,避免了传统反向代理在高可用、流量编排、监控、服务发现等方面的不足,具有云原生、高可用、动态流量编排、可观测、可扩展等特点。
最近,Easegress 发布了 2.0 版本,再次大幅增强了流量编排功能,使用户无需编写任何代码,就可以通过编排多个 API 来实现一个超级 API。本文,我们会通过编排一个 Telegram 翻译机器人来演示一下这个功能。这个机器人可以自动将收到的消息翻译为中文、日文和英文,并且,除了文字消息,还支持翻译语音和图片消息。
准备
由于机器人需要接收 Telegram 消息通知,并调用第三方 API,所以我们需要提前准备好以下各项:
根据这篇文档安装好 Easegress 的最新版本,并请确保外部应用至少可以通过 80、88、443 或 8443 端口中的一个访问到这个 Easegress 实例。
根据这篇文档创建一个 Telegram 机器人,设置好名字(本文中使用的是 EaseTranslateBot),记下它的 token,并设置一个 WebHook,WebHook 的地址指向上一步中安装的 Easegress 实例。我们的机器人将通过这个 WebHook 接收新消息通知。
AWS 的 Access Key ID 和 Access Key Secret,并确保可以通过这个 Access Key 使用 AWS 的翻译 API。
Google Cloud 的 Token,并确保可以通过这个 Token 使用 Google Cloud 的语音识别(Speech Recognize)API 和 OCR(Image Annotation)API。
您也可以使用其它厂商的翻译、语音识别或 OCR API,但这需要您对后文中的示例做相应调整。
实现原理
下图展示了这个机器人的工作流程。
收到 Telegram 服务器通过 WebHook 发来的新消息通知后,机器人首先检查消息类型,并分别进行如下处理:
文字消息:直接提取消息文本;
语音消息:这种情况下,消息体中只有语音文件的 ID,所以需要先调用 Telegram 的 API 将 ID 转换成文件地址,然后下载这个文件,并把其内容发给 Google 语音识别服务,将其转换为文本;
图片消息:前半部分基本与语音消息相同,但会将图片内容发给 Google 的 Image Annotation 服务,将其转换为文本。
经过以上处理,三种消息就都变成了文本,之后,就可以调用 AWS 的翻译服务,将其依次翻译为不同的目标语言,本文示例使用的目标语言是中文、日文和英文。
Pipeline
首先,我们来看一下 Pipeline 编排出来的总体流程:
flow:
#Telegram 要求每个请求都返回应答,但我们不会处理所有请求,所以,
#我们把 ResponseBuilder 放在最前面以确保能够返回应答。
- filter: buildFinalResponse
#检测消息类型,并跳转到对应的位置。
- filter: detectMessageType
jumpIf:
result0: processText # 文字
result1: processVoice # 语音
result2: processPhoto # 图片
“”: END # 忽略消息,直接结束处理流程
#文字消息
- filter: requestBuilderExtractText
alias: processText # 别名
namespace: extract # 所属命名空间
jumpIf: # 条件跳转,如果一切正常就开始翻译,
“”: translate # 否则会自动结束处理流程
#语音消息
- filter: requestBuilderGetVoiceFile # 构造将语音文件 ID 转换成文件路
alias: processVoice # 径的请求
namespace: extract - filter: proxyTelegram # 发送请求,得到文件路径
namespace: extract - filter: requestBuilderDownloadFile # 构造下载语音文件的请求
namespace: extract - filter: proxyTelegram # 发送请求,得到文件内容
namespace: extract - filter: requestBuilderSpeechRecognize # 构造调用语音识别 API 的请求
namespace: extract - filter: proxySpeechRecognize # 发送请求,得到识别结果
namespace: extract - filter: requestBuilderSpeechText # 保存识别结果
namespace: extract
jumpIf: # 条件跳转,如果一切正常就开始翻译,
“”: translate # 否则会自动结束处理流程
#图片消息(流程与语音消息基本相同)
- filter: requestBuilderGetPhotoFile
alias: processPhoto
namespace: extract - filter: proxyTelegram
namespace: extract - filter: requestBuilderDownloadFile
namespace: extract - filter: proxyTelegram
namespace: extract - filter: requestBuilderImageAnnotate
namespace: extract - filter: proxyImageAnnotate
namespace: extract - filter: requestBuilderPhotoText # 不使用条件跳转,正常进入翻译流程
namespace: extract
#翻译为中文
- filter: requestBuilderTranslate # 构造调用翻译 API 的请求
alias: translate
namespace: zh - filter: signAWSRequest # 根据 AWS 的要求进行签名
namespace: zh - filter: proxyTranslate # 发送请求,得到翻译结果
namespace: zh
#翻译为英文(流程与中文翻译相同)
- filter: requestBuilderTranslate
namespace: en - filter: signAWSRequest
namespace: en - filter: proxyTranslate
namespace: en
#翻译为日文(流程与中文翻译相同)
- filter: requestBuilderTranslate
namespace: ja - filter: signAWSRequest
namespace: ja - filter: proxyTranslate
namespace: ja
#回复,将翻译结果发送给 Telegram
- filter: requestBuilderReply # 发送消息回复的 API 的请求
namespace: tg - filter: proxyTelegram # 将翻译结果发送到 Telegram
namespace: tg
结合前面已经解释过的“实现原理”,我们不难看懂整个流程。但要注意,因为最终的回复需要综合多个 API 的执行结果,我们使用了多个命名空间(namespace)来保存这些 API 的调用参数和执行结果,也就是发送的请求(Request)和它们返回的应答(Response)。
为了达到更好的效果,我们还在 Pipeline 上定义了一些数据:
data:
zh:
fallback: “(抱歉,我不懂这种语言。)”
text: “中文