Google Cloud Vision via gRPC dans Delphi

· Composants

Google Cloud Vision analyse les images et vous dit ce qu'elles contiennent : il renvoie des étiquettes descriptives, lit le texte imprimé et manuscrit (OCR), détecte les visages, reconnaît les points de repère et les logos célèbres, et bien plus. sgcWebSockets Enterprise fournit un client gRPC Vision typé qui repose sur TsgcGRPCClient, ce qui vous permet d'envoyer une image et de lire ses annotations en retour depuis Delphi et C++Builder sans aucun runtime externe ni protobufs écrits à la main.

Comment ça fonctionne

Cloud Vision expose un service gRPC ImageAnnotator. Une requête est un lot d'une ou plusieurs images, chacune associée à la liste des fonctionnalités que vous voulez détecter, et la réponse est un lot correspondant d'annotations. Tout l'échange est constitué de messages Protocol Buffers encadrés sur HTTP/2.

sgcWebSockets fournit déjà une pile HTTP/2 complète, donc le transport est un TsgcHTTP2Client pointé vers vision.googleapis.com:443 via TLS. TsgcGRPCClient repose par-dessus et effectue l'encadrement gRPC, les en-têtes, les délais d'attente et l'analyse des trailers. Les classes de messages Vision dans sgcGRPC_Google_Vision sont des assistants protobuf typés : vous renseignez l'objet de requête, appelez ToBytes pour le sérialiser, l'envoyez avec le client générique, et chargez les octets de réponse dans un objet de réponse typé avec LoadFromBytes.

L'authentification est le flux standard de compte de service Google. Un JWT auto-signé est échangé contre un jeton bearer et envoyé en tant que métadonnées gRPC sur chaque appel. Comme le JWT est lié à une audience, le jeton est ciblé sur l'endpoint Vision afin que vision.googleapis.com l'accepte.

Configurer les clients

Créez le transport HTTP/2, attachez-y le client gRPC, et indiquez au canal d'utiliser le type de contenu protobuf binaire. Vision parle application/grpc+proto.

uses
  sgcHTTP2_Client, sgcGRPC_Types, sgcGRPC_Client,
  sgcGRPC_Google_Vision;

var
  HTTP2: TsgcHTTP2Client;
  GRPC: TsgcGRPCClient;
begin
  HTTP2 := TsgcHTTP2Client.Create(nil);
  HTTP2.Host := 'vision.googleapis.com';
  HTTP2.Port := 443;
  HTTP2.TLS  := True;

  GRPC := TsgcGRPCClient.Create(nil);
  GRPC.Client := HTTP2;
  GRPC.ChannelOptions.ContentType := grpcProto;
  GRPC.ChannelOptions.Compression := grpcNoCompression;
end;

Authentification

Le jeton bearer provient de vos identifiants de compte de service. Configurez les options JWT avec les valeurs de la clé JSON téléchargée, pointez l'audience vers l'endpoint Vision, et ajoutez le jeton obtenu à DefaultMetadata afin qu'il voyage sur chaque appel gRPC.

// configure the service-account JWT (values from the JSON key file)
CloudClient.GoogleCloudOptions.Authentication := gcaJWT;
CloudClient.GoogleCloudOptions.JWT.ClientEmail  := ClientEmail;
CloudClient.GoogleCloudOptions.JWT.PrivateKeyId := PrivateKeyId;
CloudClient.GoogleCloudOptions.JWT.PrivateKey.Text := PrivateKey;
CloudClient.GoogleCloudOptions.JWT.ProjectId := ProjectId;
// the self-signed JWT is audience-bound to the Vision endpoint
CloudClient.GoogleCloudOptions.JWT.API_Endpoint :=
  'https://vision.googleapis.com/';

// once the token is acquired, send it as gRPC metadata
GRPC.DefaultMetadata.Clear;
GRPC.DefaultMetadata.Add('authorization', 'Bearer ' + Token);

Annoter une image

Pour analyser une image, vous construisez un TsgcGRPCVisionBatchAnnotateImagesRequest, ajoutez une requête d'image, la pointez vers l'image (un URI Google Cloud Storage ici, mais vous pouvez aussi envoyer des octets bruts), et ajoutez une ou plusieurs fonctionnalités. Chaque fonctionnalité a un FeatureType et un MaxResults optionnel. Sérialisez avec ToBytes et appelez la méthode BatchAnnotateImages du service ImageAnnotator.

var
  oRequest: TsgcGRPCVisionBatchAnnotateImagesRequest;
  oImgReq: TsgcGRPCVisionAnnotateImageRequest;
  oFeature: TsgcGRPCVisionFeature;
  oResponse: TsgcGRPCResponse;
begin
  oRequest := TsgcGRPCVisionBatchAnnotateImagesRequest.Create;
  try
    oImgReq := oRequest.AddRequest;
    oImgReq.Image.Source.GcsImageUri :=
      'gs://cloud-samples-data/vision/demo-image.jpg';

    oFeature := oImgReq.AddFeature;
    oFeature.FeatureType := 4;   // LABEL_DETECTION
    oFeature.MaxResults := 10;

    oResponse := GRPC.Call('google.cloud.vision.v1.ImageAnnotator',
      'BatchAnnotateImages', oRequest.ToBytes);
  finally
    oRequest.Free;
  end;
end;

Les valeurs de FeatureType suivent l'énumération de l'API Vision : 1 FACE_DETECTION, 2 LANDMARK_DETECTION, 3 LOGO_DETECTION, 4 LABEL_DETECTION, 5 TEXT_DETECTION, 6 DOCUMENT_TEXT_DETECTION, et le reste. Pour exécuter plusieurs détections sur la même image en un seul aller-retour, ajoutez plus d'une fonctionnalité.

Lire les annotations

Les octets de réponse se chargent directement dans une réponse de lot typée. Chaque image du lot porte des listes distinctes pour les annotations d'étiquette, de point de repère, de logo et de texte. Chaque entrée est un TsgcGRPCVisionEntityAnnotation avec une Description et, pour les étiquettes, un Score de confiance.

var
  oResponse: TsgcGRPCVisionBatchAnnotateImagesResponse;
  oImgResp: TsgcGRPCVisionAnnotateImageResponse;
  i, j: Integer;
begin
  oResponse := TsgcGRPCVisionBatchAnnotateImagesResponse.Create;
  try
    oResponse.LoadFromBytes(aData);
    for i := 0 to oResponse.ResponseCount - 1 do
    begin
      oImgResp := oResponse.Response(i);

      for j := 0 to oImgResp.LabelAnnotationCount - 1 do
        Memo1.Lines.Add('Label: ' + oImgResp.LabelAnnotation(j).Description +
          ' (score: ' + FloatToStr(oImgResp.LabelAnnotation(j).Score) + ')');

      for j := 0 to oImgResp.TextAnnotationCount - 1 do
        Memo1.Lines.Add('Text: ' + oImgResp.TextAnnotation(j).Description);

      for j := 0 to oImgResp.LandmarkAnnotationCount - 1 do
        Memo1.Lines.Add('Landmark: ' + oImgResp.LandmarkAnnotation(j).Description);
    end;
  finally
    oResponse.Free;
  end;
end;

Images depuis le stockage ou depuis des octets

La source de l'image est flexible. Définissez Image.Source.GcsImageUri pour un objet dans Google Cloud Storage, ou Image.Source.ImageUri pour une URL HTTP(S) publique. Pour annoter un fichier local, lisez-le dans un TBytes et affectez-le plutôt à Image.Content, afin que l'image voyage en ligne dans la requête. Les mêmes classes de requête et de réponse gèrent toutes les sources.

Synchrone ou asynchrone

L'exemple ci-dessus utilise l'appel bloquant Call, qui renvoie un TsgcGRPCResponse avec le StatusCode, les octets Data bruts et les trailers. Pour garder l'interface réactive, utilisez CallAsync et gérez la réponse dans l'événement OnGRPCResponse, où vous analysez aResponse.Data exactement de la même façon. Un statut non-OK remonte via OnGRPCError, et un échec de transport via OnGRPCException.

Disponibilité

Le client gRPC Vision typé fait partie de l'édition Enterprise de sgcWebSockets et fonctionne sous Windows, macOS, Linux, iOS et Android. Un exemple prêt à l'emploi se trouve dans Demos\21.GRPC\13.Vision, et la référence complète est sur la page produit du client gRPC.

Des questions ou des commentaires ? Contactez-nous. Vous recevrez une réponse des personnes qui ont écrit le code.