Instructivo de reconocimiento óptico de caracteres (OCR)

Aprende a realizar el reconocimiento óptico de caracteres (OCR) en Google Cloud Platform. En este instructivo, se muestra como subir archivos de imagen a Google Cloud Storage, extraer el texto de las imágenes con la API de Google Cloud Vision, traducir el texto con la API de Google Cloud Translation y volver a guardar tus traducciones en Cloud Storage. Google Cloud Pub/Sub se usa para poner en cola varias tareas y activar las funciones correctas de Cloud Functions a fin de realizarlas.

Objetivos

Costos

En este instructivo, se usan los siguientes componentes facturables de Cloud Platform:

  • Google Cloud Functions
  • Google Cloud Pub/Sub
  • Google Cloud Storage
  • API de Google Cloud Translation
  • API de Google Cloud Vision

Usa la calculadora de precios para generar una estimación de los costos según el uso previsto.

Los usuarios nuevos de Cloud Platform podrían cumplir con los requisitos para obtener una prueba gratuita.

Antes de comenzar

  1. Accede a tu Cuenta de Google.

    Si todavía no tienes una cuenta, regístrate para obtener una nueva.

  2. En GCP Console, en la página de selección de proyecto, selecciona o crea un proyecto de GCP.

    Ir a la página de selección de proyecto

  3. Comprueba que la facturación esté habilitada en tu proyecto.

    Descubre cómo puedes habilitar la facturación

  4. Habilita lasCloud Functions, Cloud Pub/Sub, Cloud Storage, Cloud Translation, and Cloud VisionAPIAPI.

    Habilita lasAPI

  5. Actualiza los componentes de gcloud:
    gcloud components update
  6. Prepara tu entorno de desarrollo.

Visualiza el flujo de datos

El flujo de datos en la aplicación del instructivo de OCR incluye los siguientes pasos:

  1. Se sube a Cloud Storage una imagen con texto en cualquier idioma (texto que aparece en la propia imagen).
  2. Se activa una función de Cloud Functions que usa la API de Vision para extraer el texto y ponerlo en cola a fin de traducirlo a los idiomas de traducción configurados (mediante la publicación de un mensaje en un tema de Pub/Sub que, a su vez, desencadena otra función).
  3. Por cada traducción en cola, se activa una función de Cloud Functions que usa la API de Translation para traducir el texto y ponerlo en cola a fin de guardarlo en Cloud Storage (una vez más, mediante la publicación de un mensaje en un tema de Pub/Sub).
  4. Por cada texto traducido, se activa una función de Cloud Functions que guarda el texto traducido en Cloud Storage.

El siguiente gráfico puede ayudarte a visualizar los pasos:

Prepara la aplicación

  1. Crea un depósito de Cloud Storage para subir tus imágenes, donde YOUR_IMAGE_BUCKET_NAME es un nombre de depósito único a nivel global:

    gsutil mb gs://YOUR_IMAGE_BUCKET_NAME
    
  2. Crea un depósito de Cloud Storage para guardar las traducciones, donde YOUR_TEXT_BUCKET_NAME es un nombre de depósito único a nivel global:

    gsutil mb gs://YOUR_TEXT_BUCKET_NAME
    
  3. Clona el repositorio de la aplicación de muestra en tu máquina local con el siguiente comando:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    De forma alternativa, puedes descargar la muestra como un archivo ZIP y extraerla.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    De forma alternativa, puedes descargar la muestra como un archivo ZIP y extraerla.

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git

    De forma alternativa, puedes descargar la muestra como un archivo ZIP y extraerla.

  4. Ve al directorio que contiene el código de muestra de Cloud Functions:

    Node.js

    cd nodejs-docs-samples/functions/ocr/app/

    Python

    cd python-docs-samples/functions/ocr/app/

    Go

    cd golang-samples/functions/ocr/app/

  5. Configura la aplicación de la siguiente forma:

    Node.js

    Usa el archivo config.default.json como una plantilla y crea un archivo config.json en el directorio app con el siguiente contenido:
    {
    "RESULT_TOPIC": "YOUR_RESULT_TOPIC_NAME",
    "RESULT_BUCKET": "YOUR_TEXT_BUCKET_NAME",
    "TRANSLATE_TOPIC": "YOUR_TRANSLATE_TOPIC_NAME",
    "TRANSLATE": true,
    "TO_LANG": ["en", "fr", "es", "ja", "ru"]
    }
    • Reemplaza YOUR_RESULT_TOPIC_NAME por un nombre de tema de Pub/Sub que se use para guardar los resultados una vez que se complete la traducción.
    • Reemplaza YOUR_TEXT_BUCKET_NAME por un nombre de depósito que se use para guardar los resultados de traducción.
    • Reemplaza YOUR_TRANSLATE_TOPIC_NAME por un nombre de tema de Pub/Sub que se use para traducir el texto extraído en el paso de OCR.

    Python

    Edita el archivo config.json en el directorio app para que tenga el siguiente contenido:
    {
    "RESULT_TOPIC": "YOUR_RESULT_TOPIC_NAME",
    "RESULT_BUCKET": "YOUR_TEXT_BUCKET_NAME",
    "TRANSLATE_TOPIC": "YOUR_TRANSLATE_TOPIC_NAME",
    "TRANSLATE": true,
    "TO_LANG": ["en", "fr", "es", "ja", "ru"]
    }
    • Reemplaza YOUR_RESULT_TOPIC_NAME por un nombre de tema de Pub/Sub que se use para guardar los resultados una vez que se complete el paso de traducción.
    • Reemplaza YOUR_TEXT_BUCKET_NAME por un nombre de depósito que se use para guardar los resultados de traducción.
    • Reemplaza YOUR_TRANSLATE_TOPIC_NAME por un nombre de tema de Pub/Sub para activar la traducción del texto extraído.

    Go

    Edita el archivo config.json en el directorio app para que tenga el siguiente contenido:
    {
    "RESULT_TOPIC": "YOUR_RESULT_TOPIC_NAME",
    "RESULT_BUCKET": "YOUR_TEXT_BUCKET_NAME",
    "TRANSLATE_TOPIC": "YOUR_TRANSLATE_TOPIC_NAME",
    "TO_LANG": ["en", "fr", "es", "ja", "ru"]
    }
    • Reemplaza YOUR_RESULT_TOPIC_NAME por un nombre de tema de Pub/Sub que se use para guardar los resultados una vez que se complete la traducción.
    • Reemplaza YOUR_TEXT_BUCKET_NAME por un nombre de depósito que se use para guardar los resultados.
    • Reemplaza YOUR_TRANSLATE_TOPIC_NAME por un nombre de tema de Pub/Sub que se use para traducir los resultados.

Comprende el código

Importa dependencias

La aplicación debe importar varias dependencias con el fin de comunicarse con los servicios de Google Cloud Platform:

Node.js

const config = require('./config.json');

// Get a reference to the Pub/Sub component
const {PubSub} = require('@google-cloud/pubsub');
const pubsub = new PubSub();
// Get a reference to the Cloud Storage component
const {Storage} = require('@google-cloud/storage');
const storage = new Storage();

// Get a reference to the Cloud Vision API component
const Vision = require('@google-cloud/vision');
const vision = new Vision.ImageAnnotatorClient();

// Get a reference to the Translate API component
const {Translate} = require('@google-cloud/translate');
const translate = new Translate();

const Buffer = require('safe-buffer').Buffer;

Python

import base64
import json
import os

from google.cloud import pubsub_v1
from google.cloud import storage
from google.cloud import translate
from google.cloud import vision

vision_client = vision.ImageAnnotatorClient()
translate_client = translate.Client()
publisher = pubsub_v1.PublisherClient()
storage_client = storage.Client()

project_id = os.environ['GCP_PROJECT']

with open('config.json') as f:
    data = f.read()
config = json.loads(data)

Go


// Package ocr contains Go samples for creating OCR
// (Optical Character Recognition) Cloud functions.
package ocr

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"time"

	"cloud.google.com/go/pubsub"
	"cloud.google.com/go/storage"
	"cloud.google.com/go/translate"
	vision "cloud.google.com/go/vision/apiv1"
	"golang.org/x/text/language"
)

type configuration struct {
	ProjectID      string   `json:"PROJECT_ID"`
	ResultTopic    string   `json:"RESULT_TOPIC"`
	ResultBucket   string   `json:"RESULT_BUCKET"`
	TranslateTopic string   `json:"TRANSLATE_TOPIC"`
	ToLang         []string `json:"TO_LANG"`
}

type ocrMessage struct {
	Text     string       `json:"text"`
	FileName string       `json:"fileName"`
	Lang     language.Tag `json:"lang"`
	SrcLang  language.Tag `json:"srcLang"`
}

// GCSEvent is the payload of a GCS event.
type GCSEvent struct {
	Bucket         string    `json:"bucket"`
	Name           string    `json:"name"`
	Metageneration string    `json:"metageneration"`
	ResourceState  string    `json:"resourceState"`
	TimeCreated    time.Time `json:"timeCreated"`
	Updated        time.Time `json:"updated"`
}

// PubSubMessage is the payload of a Pub/Sub event.
type PubSubMessage struct {
	Data []byte `json:"data"`
}

var (
	visionClient    *vision.ImageAnnotatorClient
	translateClient *translate.Client
	pubsubClient    *pubsub.Client
	storageClient   *storage.Client
	config          *configuration
)

func setup(ctx context.Context) error {
	if config == nil {
		cfgFile, err := os.Open("config.json")
		if err != nil {
			return fmt.Errorf("os.Open: %v", err)
		}

		d := json.NewDecoder(cfgFile)
		config = &configuration{}
		if err = d.Decode(config); err != nil {
			return fmt.Errorf("Decode: %v", err)
		}
	}

	var err error // Prevent shadowing clients with :=.

	if visionClient == nil {
		visionClient, err = vision.NewImageAnnotatorClient(ctx)
		if err != nil {
			return fmt.Errorf("vision.NewImageAnnotatorClient: %v", err)
		}
	}

	if translateClient == nil {
		translateClient, err = translate.NewClient(ctx)
		if err != nil {
			return fmt.Errorf("translate.NewClient: %v", err)
		}
	}

	if pubsubClient == nil {
		pubsubClient, err = pubsub.NewClient(ctx, config.ProjectID)
		if err != nil {
			return fmt.Errorf("translate.NewClient: %v", err)
		}
	}

	if storageClient == nil {
		storageClient, err = storage.NewClient(ctx)
		if err != nil {
			return fmt.Errorf("storage.NewClient: %v", err)
		}
	}
	return nil
}

Procesa imágenes

La siguiente función lee un archivo de imagen que se subió desde Cloud Storage y llama a la función para detectar si la imagen contiene texto:

Node.js

/**
 * This function is exported by index.js, and is executed when
 * a file is uploaded to the Cloud Storage bucket you created
 * for uploading images.
 *
 * @param {object} event.data (Node 6) A Google Cloud Storage File object.
 * @param {object} event (Node 8+) A Google Cloud Storage File object.
 */
exports.processImage = event => {
  const file = event.data || event;

  return Promise.resolve()
    .then(() => {
      if (file.resourceState === 'not_exists') {
        // This was a deletion event, we don't want to process this
        return;
      }

      if (!file.bucket) {
        throw new Error(
          'Bucket not provided. Make sure you have a "bucket" property in your request'
        );
      }
      if (!file.name) {
        throw new Error(
          'Filename not provided. Make sure you have a "name" property in your request'
        );
      }

      return detectText(file.bucket, file.name);
    })
    .then(() => {
      console.log(`File ${file.name} processed.`);
    });
};

Python

def process_image(file, context):
    """Cloud Function triggered by Cloud Storage when a file is changed.
    Args:
        file (dict): Metadata of the changed file, provided by the triggering
                                 Cloud Storage event.
        context (google.cloud.functions.Context): Metadata of triggering event.
    Returns:
        None; the output is written to stdout and Stackdriver Logging
    """
    bucket = validate_message(file, 'bucket')
    name = validate_message(file, 'name')

    detect_text(bucket, name)

    print('File {} processed.'.format(file['name']))

Go


package ocr

import (
	"context"
	"fmt"
	"log"
)

// ProcessImage is executed when a file is uploaded to the Cloud Storage bucket you
// created for uploading images. It runs detectText, which processes the image for text.
func ProcessImage(ctx context.Context, event GCSEvent) error {
	if err := setup(ctx); err != nil {
		return fmt.Errorf("ProcessImage: %v", err)
	}
	if event.Bucket == "" {
		return fmt.Errorf("empty file.Bucket")
	}
	if event.Name == "" {
		return fmt.Errorf("empty file.Name")
	}
	if err := detectText(ctx, event.Bucket, event.Name); err != nil {
		return fmt.Errorf("detectText: %v", err)
	}
	log.Printf("File %s processed.", event.Name)
	return nil
}

La siguiente función extrae el texto de la imagen con la API de Cloud Vision y lo pone en cola para su traducción:

Node.js

/**
 * Detects the text in an image using the Google Vision API.
 *
 * @param {string} bucketName Cloud Storage bucket name.
 * @param {string} filename Cloud Storage file name.
 * @returns {Promise}
 */
function detectText(bucketName, filename) {
  let text;

  console.log(`Looking for text in image ${filename}`);
  return vision
    .textDetection(`gs://${bucketName}/${filename}`)
    .then(([detections]) => {
      const annotation = detections.textAnnotations[0];
      text = annotation ? annotation.description : '';
      console.log(`Extracted text from image (${text.length} chars)`);
      return translate.detect(text);
    })
    .then(([detection]) => {
      if (Array.isArray(detection)) {
        detection = detection[0];
      }
      console.log(`Detected language "${detection.language}" for ${filename}`);

      // Submit a message to the bus for each language we're going to translate to
      const tasks = config.TO_LANG.map(lang => {
        let topicName = config.TRANSLATE_TOPIC;
        if (detection.language === lang) {
          topicName = config.RESULT_TOPIC;
        }
        const messageData = {
          text: text,
          filename: filename,
          lang: lang,
        };

        return publishResult(topicName, messageData);
      });

      return Promise.all(tasks);
    });
}

Python

def detect_text(bucket, filename):
    print('Looking for text in image {}'.format(filename))

    futures = []

    text_detection_response = vision_client.text_detection({
        'source': {'image_uri': 'gs://{}/{}'.format(bucket, filename)}
    })
    annotations = text_detection_response.text_annotations
    if len(annotations) > 0:
        text = annotations[0].description
    else:
        text = ''
    print('Extracted text {} from image ({} chars).'.format(text, len(text)))

    detect_language_response = translate_client.detect_language(text)
    src_lang = detect_language_response['language']
    print('Detected language {} for text {}.'.format(src_lang, text))

    # Submit a message to the bus for each target language
    for target_lang in config.get('TO_LANG', []):
        topic_name = config['TRANSLATE_TOPIC']
        if src_lang == target_lang or src_lang == 'und':
            topic_name = config['RESULT_TOPIC']
        message = {
            'text': text,
            'filename': filename,
            'lang': target_lang,
            'src_lang': src_lang
        }
        message_data = json.dumps(message).encode('utf-8')
        topic_path = publisher.topic_path(project_id, topic_name)
        future = publisher.publish(topic_path, data=message_data)
        futures.append(future)
    for future in futures:
        future.result()

Go


package ocr

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"cloud.google.com/go/pubsub"
	"golang.org/x/text/language"
	visionpb "google.golang.org/genproto/googleapis/cloud/vision/v1"
)

// detectText detects the text in an image using the Google Vision API.
func detectText(ctx context.Context, bucketName, fileName string) error {
	log.Printf("Looking for text in image %v", fileName)
	maxResults := 1
	image := &visionpb.Image{
		Source: &visionpb.ImageSource{
			GcsImageUri: fmt.Sprintf("gs://%s/%s", bucketName, fileName),
		},
	}
	annotations, err := visionClient.DetectTexts(ctx, image, &visionpb.ImageContext{}, maxResults)
	if err != nil {
		return fmt.Errorf("DetectTexts: %v", err)
	}
	text := ""
	if len(annotations) > 0 {
		text = annotations[0].Description
	}
	if len(annotations) == 0 || len(text) == 0 {
		log.Printf("No text detected in image %q. Returning early.", fileName)
		return nil
	}
	log.Printf("Extracted text %q from image (%d chars).", text, len(text))

	detectResponse, err := translateClient.DetectLanguage(ctx, []string{text})
	if err != nil {
		return fmt.Errorf("DetectLanguage: %v", err)
	}
	if len(detectResponse) == 0 || len(detectResponse[0]) == 0 {
		return fmt.Errorf("DetectLanguage gave empty response")
	}
	srcLang := detectResponse[0][0].Language.String()
	log.Printf("Detected language %q for text %q.", srcLang, text)

	// Submit a message to the bus for each target language
	for _, targetLang := range config.ToLang {
		topicName := config.TranslateTopic
		if srcLang == targetLang || srcLang == "und" { // detection returns "und" for undefined language
			topicName = config.ResultTopic
		}
		targetTag, err := language.Parse(targetLang)
		if err != nil {
			return fmt.Errorf("language.Parse: %v", err)
		}
		srcTag, err := language.Parse(srcLang)
		if err != nil {
			return fmt.Errorf("language.Parse: %v", err)
		}
		message, err := json.Marshal(ocrMessage{
			Text:     text,
			FileName: fileName,
			Lang:     targetTag,
			SrcLang:  srcTag,
		})
		if err != nil {
			return fmt.Errorf("json.Marshal: %v", err)
		}
		topic := pubsubClient.Topic(topicName)
		ok, err := topic.Exists(ctx)
		if err != nil {
			return fmt.Errorf("Exists: %v", err)
		}
		if !ok {
			topic, err = pubsubClient.CreateTopic(ctx, topicName)
			if err != nil {
				return fmt.Errorf("CreateTopic: %v", err)
			}
		}
		msg := &pubsub.Message{
			Data: []byte(message),
		}
		if _, err = topic.Publish(ctx, msg).Get(ctx); err != nil {
			return fmt.Errorf("Get: %v", err)
		}
	}
	return nil
}

Traduce el texto

La siguiente función traduce el texto extraído y, luego, lo pone en cola para volver a guardarlo en Cloud Storage:

Node.js

/**
 * This function is exported by index.js, and is executed when
 * a message is published to the Cloud Pub/Sub topic specified
 * by the TRANSLATE_TOPIC value in the config.json file. The
 * function translates text using the Google Translate API.
 *
 * @param {object} event.data (Node 6) The Cloud Pub/Sub Message object.
 * @param {object} event (Node 8+) The Cloud Pub/Sub Message object.
 * @param {string} {messageObject}.data The "data" property of the Cloud Pub/Sub
 * Message. This property will be a base64-encoded string that you must decode.
 */
exports.translateText = event => {
  const pubsubData = event.data.data || event.data;
  const jsonStr = Buffer.from(pubsubData, 'base64').toString();
  const payload = JSON.parse(jsonStr);

  return Promise.resolve()
    .then(() => {
      if (!payload.text) {
        throw new Error(
          'Text not provided. Make sure you have a "text" property in your request'
        );
      }
      if (!payload.filename) {
        throw new Error(
          'Filename not provided. Make sure you have a "filename" property in your request'
        );
      }
      if (!payload.lang) {
        throw new Error(
          'Language not provided. Make sure you have a "lang" property in your request'
        );
      }

      console.log(`Translating text into ${payload.lang}`);
      return translate.translate(payload.text, payload.lang);
    })
    .then(([translation]) => {
      const messageData = {
        text: translation,
        filename: payload.filename,
        lang: payload.lang,
      };

      return publishResult(config.RESULT_TOPIC, messageData);
    })
    .then(() => {
      console.log(`Text translated to ${payload.lang}`);
    });
};

Python

def translate_text(event, context):
    if event.get('data'):
        message_data = base64.b64decode(event['data']).decode('utf-8')
        message = json.loads(message_data)
    else:
        raise ValueError('Data sector is missing in the Pub/Sub message.')

    text = validate_message(message, 'text')
    filename = validate_message(message, 'filename')
    target_lang = validate_message(message, 'lang')
    src_lang = validate_message(message, 'src_lang')

    print('Translating text into {}.'.format(target_lang))
    translated_text = translate_client.translate(text,
                                                 target_language=target_lang,
                                                 source_language=src_lang)
    topic_name = config['RESULT_TOPIC']
    message = {
        'text': translated_text['translatedText'],
        'filename': filename,
        'lang': target_lang,
    }
    message_data = json.dumps(message).encode('utf-8')
    topic_path = publisher.topic_path(project_id, topic_name)
    future = publisher.publish(topic_path, data=message_data)
    future.result()

Go


package ocr

import (
	"context"
	"encoding/json"
	"fmt"
	"log"

	"cloud.google.com/go/pubsub"
	"cloud.google.com/go/translate"
)

// TranslateText is executed when a message is published to the Cloud Pub/Sub topic specified
// by TRANSLATE_TOPIC in config.json, and translates the text using the Google Translate API.
func TranslateText(ctx context.Context, event PubSubMessage) error {
	if err := setup(ctx); err != nil {
		return fmt.Errorf("setup: %v", err)
	}
	if event.Data == nil {
		return fmt.Errorf("empty data")
	}
	var message ocrMessage
	if err := json.Unmarshal(event.Data, &message); err != nil {
		return fmt.Errorf("json.Unmarshal: %v", err)
	}

	log.Printf("Translating text into %s.", message.Lang.String())
	opts := translate.Options{
		Source: message.SrcLang,
	}
	translateResponse, err := translateClient.Translate(ctx, []string{message.Text}, message.Lang, &opts)
	if err != nil {
		return fmt.Errorf("Translate: %v", err)
	}
	if len(translateResponse) == 0 {
		return fmt.Errorf("Empty Translate response")
	}
	translatedText := translateResponse[0]

	messageData, err := json.Marshal(ocrMessage{
		Text:     translatedText.Text,
		FileName: message.FileName,
		Lang:     message.Lang,
		SrcLang:  message.SrcLang,
	})
	if err != nil {
		return fmt.Errorf("json.Marshal: %v", err)
	}

	topic := pubsubClient.Topic(config.ResultTopic)
	ok, err := topic.Exists(ctx)
	if err != nil {
		return fmt.Errorf("Exists: %v", err)
	}
	if !ok {
		topic, err = pubsubClient.CreateTopic(ctx, config.ResultTopic)
		if err != nil {
			return fmt.Errorf("CreateTopic: %v", err)
		}
	}
	msg := &pubsub.Message{
		Data: messageData,
	}
	if _, err = topic.Publish(ctx, msg).Get(ctx); err != nil {
		return fmt.Errorf("Get: %v", err)
	}
	log.Printf("Sent translation: %q", translatedText.Text)
	return nil
}

Guarda las traducciones

Por último, la siguiente función recibe el texto traducido y lo vuelve a guardar en Cloud Storage:

Node.js

/**
 * This function is exported by index.js, and is executed when
 * a message is published to the Cloud Pub/Sub topic specified
 * by the RESULT_TOPIC value in the config.json file. The
 * function saves the data packet to a file in GCS.
 *
 * @param {object} event.data (Node 6) The Cloud Pub/Sub Message object.
 * @param {object} event (Node 8+) The Cloud Pub/Sub Message object.
 * @param {string} {messageObject}.data The "data" property of the Cloud Pub/Sub
 * Message. This property will be a base64-encoded string that you must decode.
 */
exports.saveResult = event => {
  const pubsubData = event.data.data || event.data;
  const jsonStr = Buffer.from(pubsubData, 'base64').toString();
  const payload = JSON.parse(jsonStr);

  return Promise.resolve()
    .then(() => {
      if (!payload.text) {
        throw new Error(
          'Text not provided. Make sure you have a "text" property in your request'
        );
      }
      if (!payload.filename) {
        throw new Error(
          'Filename not provided. Make sure you have a "filename" property in your request'
        );
      }
      if (!payload.lang) {
        throw new Error(
          'Language not provided. Make sure you have a "lang" property in your request'
        );
      }

      console.log(`Received request to save file ${payload.filename}`);

      const bucketName = config.RESULT_BUCKET;
      const filename = renameImageForSave(payload.filename, payload.lang);
      const file = storage.bucket(bucketName).file(filename);

      console.log(`Saving result to ${filename} in bucket ${bucketName}`);

      return file.save(payload.text);
    })
    .then(() => {
      console.log(`File saved.`);
    });
};

Python

def save_result(event, context):
    if event.get('data'):
        message_data = base64.b64decode(event['data']).decode('utf-8')
        message = json.loads(message_data)
    else:
        raise ValueError('Data sector is missing in the Pub/Sub message.')

    text = validate_message(message, 'text')
    filename = validate_message(message, 'filename')
    lang = validate_message(message, 'lang')

    print('Received request to save file {}.'.format(filename))

    bucket_name = config['RESULT_BUCKET']
    result_filename = '{}_{}.txt'.format(filename, lang)
    bucket = storage_client.get_bucket(bucket_name)
    blob = bucket.blob(result_filename)

    print('Saving result to {} in bucket {}.'.format(result_filename,
                                                     bucket_name))

    blob.upload_from_string(text)

    print('File saved.')

Go


package ocr

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
)

// SaveResult is executed when a message is published to the Cloud Pub/Sub topic specified by
// RESULT_TOPIC in config.json file, and saves the data packet to a file in GCS.
func SaveResult(ctx context.Context, event PubSubMessage) error {
	if err := setup(ctx); err != nil {
		return fmt.Errorf("ProcessImage: %v", err)
	}
	var message ocrMessage
	if event.Data == nil {
		return fmt.Errorf("Empty data")
	}
	if err := json.Unmarshal(event.Data, &message); err != nil {
		return fmt.Errorf("json.Unmarshal: %v", err)
	}
	log.Printf("Received request to save file %q.", message.FileName)

	bucketName := config.ResultBucket
	resultFilename := fmt.Sprintf("%s_%s.txt", message.FileName, message.Lang)
	bucket := storageClient.Bucket(bucketName)

	log.Printf("Saving result to %q in bucket %q.", resultFilename, bucketName)

	w := bucket.Object(resultFilename).NewWriter(ctx)
	defer w.Close()
	fmt.Fprint(w, message.Text)

	log.Printf("File saved.")
	return nil
}

Implementa las funciones

En esta sección, se describe cómo implementar las funciones.

  1. Para implementar la función de procesamiento de imágenes con un activador de Cloud Storage, ejecuta el siguiente comando en el directorio app:

    Node.js 8

    gcloud functions deploy ocr-extract --runtime nodejs8 --trigger-bucket YOUR_IMAGE_BUCKET_NAME --entry-point processImage

    Node.js 10 (Beta)

    gcloud functions deploy ocr-extract --runtime nodejs10 --trigger-bucket YOUR_IMAGE_BUCKET_NAME --entry-point processImage

    Node.js 6 (obsoleta)

    gcloud functions deploy ocr-extract --runtime nodejs6 --trigger-bucket YOUR_IMAGE_BUCKET_NAME --entry-point processImage

    Python

    gcloud functions deploy ocr-extract --runtime python37 --trigger-bucket YOUR_IMAGE_BUCKET_NAME --entry-point process_image

    Go

    gcloud functions deploy ocr-extract --runtime go111 --trigger-bucket YOUR_IMAGE_BUCKET_NAME --entry-point ProcessImage

    donde YOUR_IMAGE_BUCKET_NAME es el nombre del depósito de Cloud Storage al que subirás las imágenes.

  2. Para implementar la función de traducción de texto con un activador de Cloud Pub/Sub, ejecuta el siguiente comando en el directorio app:

    Node.js 8

    gcloud functions deploy ocr-translate --runtime nodejs8 --trigger-topic YOUR_TRANSLATE_TOPIC_NAME --entry-point translateText

    Node.js 10 (Beta)

    gcloud functions deploy ocr-translate --runtime nodejs10 --trigger-topic YOUR_TRANSLATE_TOPIC_NAME --entry-point translateText

    Node.js 6 (obsoleta)

    gcloud functions deploy ocr-translate --runtime nodejs6 --trigger-topic YOUR_TRANSLATE_TOPIC_NAME --entry-point translateText

    Python

    gcloud functions deploy ocr-translate  --runtime python37 --trigger-topic YOUR_TRANSLATE_TOPIC_NAME --entry-point translate_text

    Go

    gcloud functions deploy ocr-translate --runtime go111 --trigger-topic YOUR_TRANSLATE_TOPIC_NAME --entry-point TranslateText

    donde YOUR_TRANSLATE_TOPIC_NAME es el nombre de tema de Cloud Pub/Sub con el que se activarán las traducciones.

  3. Para implementar la función que guarda los resultados en Cloud Storage con un activador de Cloud Pub/Sub, ejecuta el siguiente comando en el directorio app:

    Node.js 8

    gcloud functions deploy ocr-save --runtime nodejs8 --trigger-topic YOUR_RESULT_TOPIC_NAME --entry-point saveResult

    Node.js 10 (Beta)

    gcloud functions deploy ocr-save --runtime nodejs10 --trigger-topic YOUR_RESULT_TOPIC_NAME --entry-point saveResult

    Node.js 6 (obsoleta)

    gcloud functions deploy ocr-save --runtime nodejs6 --trigger-topic YOUR_RESULT_TOPIC_NAME --entry-point saveResult

    Python

    gcloud functions deploy ocr-save --runtime python37 --trigger-topic YOUR_RESULT_TOPIC_NAME --entry-point save_result

    Go

    gcloud functions deploy ocr-save --runtime go111 --trigger-topic YOUR_RESULT_TOPIC_NAME --entry-point SaveResult

    donde YOUR_RESULT_TOPIC_NAME es el nombre de tema de Cloud Pub/Sub con el que se activará la función para guardar los resultados.

Sube una imagen

  1. Sube una imagen al depósito de imágenes de Cloud Storage:

    gsutil cp PATH_TO_IMAGE gs://YOUR_IMAGE_BUCKET_NAME
    

    donde:

    • PATH_TO_IMAGE es una ruta de acceso al archivo de imagen (que contiene texto) en tu sistema local.
    • YOUR_IMAGE_BUCKET_NAME es el nombre del depósito al que subes las imágenes.

    Puedes descargar una de las imágenes desde el proyecto de muestra.

  2. Revisa los registros para asegurarte de que las ejecuciones se completaron:

    gcloud functions logs read --limit 100
    
  3. Puedes ver las traducciones guardadas en el depósito de Cloud Storage que especifica el valor RESULT_BUCKET en tu archivo de configuración.

Realiza una limpieza

Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud Platform por los recursos que usaste en este instructivo:

Borra el proyecto

La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.

Para borrar el proyecto, sigue estos pasos:

  1. En GCP Console, dirígete a la página Administrar recursos.

    Ir a la página Administración de recursos

  2. En la lista de proyectos, selecciona el proyecto que deseas borrar y haz clic en Borrar .
  3. En el cuadro de diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

Borra las funciones de Cloud Functions

Borrar las funciones de Cloud Functions no quita ningún recurso almacenado en Cloud Storage.

Para borrar una función de Cloud Functions, ejecuta el siguiente comando:

gcloud functions delete NAME_OF_FUNCTION

donde NAME_OF_FUNCTION es el nombre de la función que se borrará.

También puedes borrar las funciones de Cloud Functions desde Google Cloud Platform Console.