Crear una herramienta de OCR de documentos con GCP OCR y Node.js
El reconocimiento óptico de caracteres (OCR) libera el contenido de texto que hay dentro de imágenes y PDF, y habilita funciones como documentos con búsqueda, entrada automatizada de datos y análisis de contenido. En este DevTip, crearemos una herramienta de OCR de documentos con GCP OCR y Node.js para extraer texto de imágenes y PDF de forma eficiente en tus aplicaciones.
Introducción
GCP OCR, impulsado por la API de Google Cloud Vision, ofrece sólidas capacidades de análisis de imágenes, incluido el OCR para la extracción de texto. Integrar este servicio en tu aplicación de Node.js te permite procesar imágenes y PDF de forma programática y extraer datos de texto de manera eficiente.
Esta guía te muestra cómo configurar la API de Google Cloud Vision, autenticar tu aplicación y escribir código de Node.js para aplicar OCR a imágenes y PDF.
Requisitos previos
Asegúrate de contar con lo siguiente:
- Una cuenta de Google Cloud Platform (GCP)
- Node.js versión 22 o posterior instalado
- Conocimientos básicos de JavaScript y Node.js
Configuración de la API de Google Cloud Vision
1. Crear un proyecto de GCP
- Ve a la Google Cloud Console.
- Haz clic en el menú desplegable de proyectos y selecciona Proyecto nuevo.
- Escribe un nombre de proyecto y haz clic en Crear.
- Habilita la facturación del proyecto.
2. Habilitar la API de Vision
- En la Cloud Console, ve a APIs y servicios > Biblioteca.
- Busca Cloud Vision API.
- Haz clic en Cloud Vision API y luego en Habilitar.
Configuración de la autenticación
-
Crea una clave de cuenta de servicio:
- Ve a IAM y administración > Cuentas de servicio
- Crea una cuenta de servicio nueva o selecciona una existente
- Crea una clave nueva (formato JSON)
- Descarga el archivo de clave JSON y guárdalo de forma segura
-
Configura la autenticación en tu aplicación:
const vision = require('@google-cloud/vision') const client = new vision.ImageAnnotatorClient({ keyFilename: 'path/to/your/service-account-key.json', })O usa variables de entorno:
export GOOGLE_APPLICATION_CREDENTIALS="path/to/your/service-account-key.json"
Mantén los archivos de clave fuera de tu repositorio. Los ejemplos siguientes usan Application
Default Credentials, que también pueden usar una cuenta de servicio adjunta en Google Cloud o
credenciales locales configuradas con gcloud auth application-default login.
Instalar la biblioteca cliente de Google Cloud Vision
Inicializa un proyecto nuevo de Node.js e instala la biblioteca necesaria:
mkdir ocr-project
cd ocr-project
npm init -y
npm install @google-cloud/vision@4 @google-cloud/storage@7
Escribir el código de Node.js
Crea un archivo index.js en el directorio de tu proyecto. Este ejemplo de CommonJS procesa
imágenes individuales; para documentos de varias páginas, usa la API de archivos PDF/TIFF
independiente que aparece más abajo:
// index.js
const vision = require('@google-cloud/vision');
// Creates a client
const client = new vision.ImageAnnotatorClient();
async function extractTextFromImage(imagePath) {
try {
const [result] = await client.textDetection(imagePath);
if (result.error?.code) {
throw Object.assign(new Error('Vision text detection failed', { cause: result.error }), {
code: result.error.code,
});
}
const detections = result.textAnnotations ?? [];
return detections.map(text => text.description);
} catch (error) {
if (error.code === 8) {
console.error('API quota exceeded');
} else if (error.code === 7) {
console.error('Permission denied: check IAM permissions and API enablement');
}
throw error;
}
}
// Example usage
extractTextFromImage('images/sample.jpg')
.then(text => console.log('Extracted text:', text))
.catch(error => {
console.error('OCR failed:', error.message);
process.exitCode = 1;
});
Procesar archivos PDF
Para extraer texto de PDF, usa la función de anotación por lotes asíncrona con Google Cloud Storage.
Primero, sube el PDF a un bucket privado. La identidad que hace la llamada necesita permiso para leer
la entrada, crear objetos de salida, y listar y leer esas salidas. Proporciona un prefijo de salida
nuevo y vacío que termine en / para cada trabajo, de modo que los resultados no puedan
mezclarse con trabajos anteriores. Reutiliza client de arriba:
const { Storage } = require('@google-cloud/storage');
const storage = new Storage();
async function extractTextFromPDF(gcsSourceUri, gcsDestinationUri) {
const destination = /^gs:\/\/([^/]+)\/(.+\/)$/u.exec(gcsDestinationUri);
if (!destination) {
throw new Error('Use a gs://bucket/unique-output-prefix/ destination');
}
const [, bucketName, prefix] = destination;
const inputConfig = {
mimeType: 'application/pdf',
gcsSource: {
uri: gcsSourceUri
}
};
const outputConfig = {
gcsDestination: {
uri: gcsDestinationUri
},
batchSize: 1
};
const features = [{ type: 'DOCUMENT_TEXT_DETECTION' }];
const request = {
requests: [{
inputConfig,
features,
outputConfig,
}]
};
const [operation] = await client.asyncBatchAnnotateFiles(request);
await operation.promise();
// The operation returns output locations; OCR text lives in the JSON objects in Storage.
const [files] = await storage.bucket(bucketName).getFiles({ prefix });
const pages = [];
for (const file of files.filter(file => file.name.endsWith('.json'))) {
const [contents] = await file.download();
const result = JSON.parse(contents.toString('utf8'));
if (result.error?.code) {
throw Object.assign(new Error('PDF file failed', { cause: result.error }), {
code: result.error.code,
});
}
for (const page of result.responses ?? []) {
if (page.error?.code) {
throw Object.assign(new Error('PDF page failed', { cause: page.error }), {
code: page.error.code,
});
}
if (!Number.isInteger(page.context?.pageNumber)) {
throw new Error('PDF result is missing its page number');
}
pages.push({ number: page.context.pageNumber, text: page.fullTextAnnotation?.text ?? '' });
}
}
if (pages.length === 0) throw new Error('Vision returned no PDF pages');
return pages.sort((a, b) => a.number - b.number).map(page => page.text).join('\n');
}
Llama a extractTextFromPDF('gs://your-input-bucket/document.pdf', 'gs://your-output-bucket/unique-job-id/') y maneja su promesa rechazada como en el ejemplo de la imagen.
Para entradas TIFF, usa image/tiff como tipo MIME. Configura una política de ciclo de vida del
almacenamiento adecuada para tus documentos y para la salida del OCR; el ejemplo conserva ambos.
Cierra el cliente de Vision compartido con await client.close() cuando termine todo el trabajo en una
aplicación de CLI.
Consulta la guía de OCR para PDF/TIFF de Google para conocer los formatos de solicitud y de salida.
Limitaciones y precios de la API
- Límite de procesamiento de PDF: 2.000 páginas por archivo
- Cada página PDF/TIFF cuenta como una imagen individual para la facturación; cinco páginas son cinco unidades por función, incluso cuando se agrupan en una sola solicitud o en un único archivo de salida.
- Consulta los precios de Cloud Vision para conocer las tarifas actuales del nivel gratuito y por volumen. Los cargos de Cloud Storage son aparte.
Configuración regional
Si tienes requisitos de residencia de datos, puedes especificar endpoints regionales:
const client = new vision.ImageAnnotatorClient({
apiEndpoint: 'eu-vision.googleapis.com', // European Union
// or 'us-vision.googleapis.com' // United States
})
Solución de problemas
Problemas comunes y soluciones
-
Errores de autenticación
- Verifica la ruta del archivo de clave de la cuenta de servicio
- Asegúrate de que la cuenta de servicio tenga los permisos adecuados
- Comprueba si la API está habilitada en tu proyecto
-
Problemas de procesamiento de PDF
- Confirma que el archivo PDF no tenga más de 2.000 páginas
- Verifica los permisos del bucket de GCS
- Comprueba la compatibilidad del formato del archivo PDF
-
Limitación de frecuencia
- Implementa un retroceso exponencial para los reintentos
- Supervisa el uso de la cuota en la GCP Console
- Considera el procesamiento por lotes para volúmenes grandes
Buenas prácticas
-
Manejo de errores
async function processDocument(filePath) { try { const result = await extractTextFromImage(filePath); return result; } catch (error) { if (error.code === 'ENOENT') { throw new Error('File not found', { cause: error }); } if (error.code === 8) { throw new Error('API quota exceeded', { cause: error }); } if (error.code === 7) { throw new Error('Permission denied: check IAM permissions and API enablement', { cause: error, }); } throw error; } } -
Procesamiento por lotes
async function processBatch(files, concurrency = 3) { if (!Number.isInteger(concurrency) || concurrency < 1) { throw new Error('Concurrency must be a positive integer'); } const results = []; for (let i = 0; i < files.length; i += concurrency) { const batch = files.slice(i, i + concurrency); const batchResults = await Promise.all( batch.map(file => processDocument(file).catch(() => ({ error: 'Image OCR failed' }))) ); results.push(...batchResults); await new Promise(resolve => setTimeout(resolve, 1000)); // Rate limiting } return results; }
Conclusión
Integrar GCP OCR en tus aplicaciones de Node.js habilita potentes capacidades de OCR. Al automatizar la extracción de texto de imágenes y PDF, puedes ampliar la funcionalidad de tu aplicación, agilizar los flujos de trabajo y aportar más valor a tus usuarios.
Transloadit también ofrece un Robot Document OCR como parte de nuestro servicio de inteligencia artificial para un procesamiento de OCR fluido y escalable.
