在 Delphi 中通过 gRPC 使用 Google Cloud Translation

· 组件

Google Cloud Translation v3 可以在一百多种语言之间翻译文本,并能为你检测一段文本的语言。该服务通过 gRPC 对外提供,而 sgcWebSockets Enterprise 提供了一个基于 TsgcGRPCClient 构建的强类型 Translation gRPC 客户端。你无需手工组装 Protocol Buffers,只需填充一个请求对象,调用一个方法,就能直接从一个强类型响应中读取翻译后的文本。本文将逐步讲解它的工作原理,并展示捆绑 demo 中的实际 Delphi 代码。

工作原理

gRPC 是通过 HTTP/2 封帧的 Protocol Buffers,因此 Translation 客户端运行在 sgcWebSockets HTTP/2 栈之上。你创建一个指向 translate.googleapis.com 端口 443、启用 TLS 的 TsgcHTTP2Client,将它赋给一个 TsgcGRPCClient,gRPC 组件就会替你完成消息封帧、请求头和流处理。

Translation 单元 sgcGRPC_Google_Translation 添加了与 v3 API 镜像对应的强类型消息类:用于翻译的 TsgcGRPCTranslationTranslateTextRequest...TranslateTextResponse、用于语言检测的 DetectLanguage 配对,以及用于列出语言的 GetSupportedLanguages 配对。每个请求都提供一个 ToBytes 方法将其序列化为 protobuf,每个响应都提供一个 LoadFromBytes 方法来解析回复。你将这些字节传递给 gRPC 客户端的 Call 方法并读回结果。

身份验证

Cloud Translation 需要一个 Google 服务账号令牌。该 demo 使用服务账号 JSON 密钥(客户端电子邮件、私钥 id、私钥和项目 id)进行身份验证并获取一个 Bearer 令牌,随后将其作为 gRPC 元数据添加,以便它随每个调用一起传递。

GetGRPCClient.DefaultMetadata.Clear;
GetGRPCClient.DefaultMetadata.Add('authorization', 'Bearer ' + FToken);

有一个细节值得注意:自签名的服务账号 JWT 是受众绑定的,因此该令牌必须以 Translation 端点为目标,才能被 translate.googleapis.com 接受。该 demo 在请求令牌之前将 JWT.API_Endpoint 设置为 https://translate.googleapis.com/

设置客户端

HTTP/2 传输和 gRPC 客户端只需连接搭建一次。Translation 服务在传输上期望 protobuf,因此通道内容类型是 grpcProto

uses
  sgcHTTP2_Client, sgcGRPC_Types, sgcGRPC_Client,
  sgcGRPC_Google_Translation;

FHTTP2Client := TsgcHTTP2Client.Create(nil);
FHTTP2Client.Host := 'translate.googleapis.com';
FHTTP2Client.Port := 443;
FHTTP2Client.TLS  := True;

FGRPCClient := TsgcGRPCClient.Create(nil);
FGRPCClient.Client := FHTTP2Client;
FGRPCClient.ChannelOptions.ContentType  := grpcProto;
FGRPCClient.ChannelOptions.Compression  := grpcNoCompression;

翻译文本

要翻译,请填充一个 TsgcGRPCTranslationTranslateTextRequest:设置 Parent 资源路径,向 Contents 添加一个或多个字符串,设置源语言代码、目标语言代码和 MIME 类型。用 ToBytes 将其序列化,并连同完全限定的服务名和方法传给 Call。父路径遵循 v3 的形式 projects/<project-id>/locations/global

var
  oRequest: TsgcGRPCTranslationTranslateTextRequest;
  oResponse: TsgcGRPCResponse;
begin
  oRequest := TsgcGRPCTranslationTranslateTextRequest.Create;
  try
    oRequest.Parent := 'projects/' + txtProjectId.Text + '/locations/global';
    oRequest.Contents.Add(txtSourceText.Text);
    oRequest.SourceLanguageCode := txtSourceLang.Text;   // e.g. 'en'
    oRequest.TargetLanguageCode := txtTargetLang.Text;   // e.g. 'es'
    oRequest.MimeType := 'text/plain';

    oResponse := GetGRPCClient.Call
      ('google.cloud.translation.v3.TranslationService', 'TranslateText',
      oRequest.ToBytes);
  finally
    oRequest.Free;
  end;
end;

回复以一个 TsgcGRPCResponse 的形式返回。当 StatusCodegrpcOK 时,将原始的 Data 字节加载到一个强类型响应中并读取每个翻译。每个 Translation 都携带 TranslatedText,并且当源语言是自动检测时,还携带 DetectedLanguageCode

var
  oResponse: TsgcGRPCTranslationTranslateTextResponse;
  i: Integer;
begin
  oResponse := TsgcGRPCTranslationTranslateTextResponse.Create;
  try
    oResponse.LoadFromBytes(aData);
    for i := 0 to oResponse.TranslationCount - 1 do
    begin
      DoLog('Translated: ' + oResponse.Translation(i).TranslatedText);
      if oResponse.Translation(i).DetectedLanguageCode <> '' then
        DoLog('Detected: ' + oResponse.Translation(i).DetectedLanguageCode);
    end;
  finally
    oResponse.Free;
  end;
end;

检测语言

当你不知道源语言时,先把翻译放在一边,调用 DetectLanguage。构建一个带有父路径和要检查的 ContentTsgcGRPCTranslationDetectLanguageRequest,然后读回候选语言,每个都带有一个 LanguageCode 和一个 Confidence 值。

oRequest := TsgcGRPCTranslationDetectLanguageRequest.Create;
try
  oRequest.Parent := GetParentPath;
  oRequest.Content := txtSourceText.Text;
  oRequest.MimeType := 'text/plain';

  oResponse := GetGRPCClient.Call
    ('google.cloud.translation.v3.TranslationService', 'DetectLanguage',
    oRequest.ToBytes);
finally
  oRequest.Free;
end;

解析检测响应会为每个候选给出语言代码和一个置信度分数。

oResponse := TsgcGRPCTranslationDetectLanguageResponse.Create;
try
  oResponse.LoadFromBytes(aData);
  for i := 0 to oResponse.LanguageCount - 1 do
    DoLog('Language: ' + oResponse.Language(i).LanguageCode +
      ' (confidence: ' + FloatToStr(oResponse.Language(i).Confidence) + ')');
finally
  oResponse.Free;
end;

列出支持的语言

第三个操作 GetSupportedLanguages 返回该服务支持的每一种语言。将 DisplayLanguageCode 设置为你希望显示名称所用的语言,每个条目就会带着一个 LanguageCode 和一个人类可读的 DisplayName 返回,并附带标志,表明它是否可用作源语言或目标语言。

oRequest := TsgcGRPCTranslationGetSupportedLanguagesRequest.Create;
try
  oRequest.Parent := GetParentPath;
  oRequest.DisplayLanguageCode := 'en';

  oResponse := GetGRPCClient.Call
    ('google.cloud.translation.v3.TranslationService',
    'GetSupportedLanguages', oRequest.ToBytes);
finally
  oRequest.Free;
end;

可用性

Translation gRPC 客户端是 sgcWebSockets Enterprise 版本的一部分,可在 Windows、macOS、Linux、iOS 和 Android 上、跨 Delphi 和 C++Builder 运行。一个完整、开箱即用的示例,包含服务账号加载和全部三个操作,位于 Demos\21.GRPC\12.Translation,底层 gRPC 客户端的文档请见gRPC Client 产品页面

有问题或反馈?联系我们。你会收到来自编写这段代码的人的回复。