首页 > 解决方案 > 如何在 Google Cloud Functions 中使用 NodeJS 链接 writeFile() 和 OCR?

问题描述

场景如下:

从 Amazon S3 存储桶中提取文件,然后将其存储在临时文件夹中,然后使用 API 执行对象字符识别。不幸的是,这不起作用,我认为这是由于异步/同步执行,但我已经尝试了几种带有回调/承诺的变体,但没有进一步。如果有人能给我一个关于如何构建这个场景的提示,我将不胜感激!

当前的错误是:

TypeError: Cannot read property 'writeFile' of undefined at Response.<anonymous> (/srv/index.js:38:32) (it's the 'await fs.writeFile(dir,data);' line)


/**
 * Responds to any HTTP request.
 *
 * @param {!express:Request} req HTTP request context.
 * @param {!express:Response} res HTTP response context.
 */
const AWS = require('aws-sdk');
const fs = require('fs').promises;
const Vision = require('@google-cloud/vision');
var os = require('os');

exports.helloWorld = async (req,res) => {

    var bucket, fileName, fileUrl;
    req.on('data', chunk => {
        body += chunk.toString();
        data.push(chunk);
    });
    req.on('end', () => {
        bucket = JSON.parse(data).value1;
        fileName = JSON.parse(data).value2;
        fileUrl = JSON.parse(data).value3;

        var s3 = new AWS.S3();

        s3.getObject({
                Bucket: bucket,
                Key: fileName
            },
            async function(error, data) {
                if (error != null) {
                    console.log("Failed to retrieve an object: " + error);
                } else {
                    console.log("Loaded " + data.ContentType + " bytes");
                    var tmpdir = os.tmpdir();
                    var dir = tmpdir+'/'+fileName;
                    try{
                      await fs.writeFile(dir,data);
                      const vision = new Vision.ImageAnnotatorClient();
                      let text;
                      await vision
                          .textDetection('/tmp/' + fileName)
                          .then(([detections]) => {
                              const annotation = detections.textAnnotations[0];
                              console.log(1);
                              text = annotation ? annotation.description : '';
                              console.log(`Extracted text from image (${text.length} chars)`);
                              console.log(1);
                              console.log(text);
                              resolve("Finished ocr successfully");
                          })
                          .catch(error =>{
                            console.log(error);
                            reject("Error with OCR");
                          })
                    }catch(error){
                      console.log(error);
                    }
                }
            },
        );

        let message = bucket + fileName + fileUrl;
        res.status(200).send(message);
    });
};

标签: node.jsgoogle-cloud-platformgoogle-cloud-functions

解决方案


您收到该错误,因为您在旧版本的 Node ( < 10.0.0)上运行,该版本fs.promises不可用。这就是为什么fs是未定义的,你得到:

TypeError: Cannot read property 'writeFile' of undefined at Response.<anonymous> (/srv/index.js:38:32) (it's the 'await fs.writeFile(dir,data);' line)

要么使用更新的版本,要么只是承诺代码。

const { promisify } = require('util');
const fs = require('fs');
// const fs = require('fs').promises

const writeFile = promisify(fs.writeFile);

现在在您的代码中使用writeFile而不是。fs.writeFile


除此之外,您的代码还有一些问题。

 req.on('data', chunk => {
        body += chunk.toString();
        data.push(chunk);
    });

dataJSON.parse没有在任何地方定义,考虑到接下来的几行,将数据推送到数组然后在该数组上运行是没有意义的。

bucket = JSON.parse(data).value1;
fileName = JSON.parse(data).value2;
fileUrl = JSON.parse(data).value3;

此外,JSON.parse应该只调用一次,而不是解析相同的字符串(这是代码中的数组,会产生错误)3 次。

const values = JSON.parse(body); // should be body instead of data with the posted code
bucket = values.value1;
fileName = values.value2;
fileUrl = values.value3;

这可以通过发布来大大改善bucket,而不是fileNamefileUrlJSONvalueN

const { bucket, fileName, fileUrl } = JSON.parse(body);

整个代码可以重写为:

const AWS = require('aws-sdk');
const { promisify } = require('util');
const fs = require('fs');
const Vision = require('@google-cloud/vision');
const os = require('os');
const path = require('path');

const writeFile = promisify(fs.writeFile);


exports.helloWorld = async (req,res) => {

    let body = '';
    req.on('data', chunk => {
        body += chunk.toString();        
    });

    req.on('end', async() => {
        // post { "bucket": "x", "fileName": "x", "fileUrl": "x" }
        const { bucket, fileName, fileUrl } = JSON.parse(body);

        var s3 = new AWS.S3();

        try {

          const data = await s3.getObject({
            Bucket: bucket,
            Key: fileName
          }).promise();

          const tmpdir = os.tmpdir();
          const filePath = path.join(tmpdir, fileName)

          await writeFile(filePath, data);

          const vision = new Vision.ImageAnnotatorClient();          
          const [detections] = await vision.textDetection(filePath)
          const annotation = detections.textAnnotations[0];
          const text = annotation ? annotation.description : '';
          console.log(`Extracted text from image (${text.length} chars)`);


          let message = bucket + fileName + fileUrl;
          res.status(200).send(message);

        } catch(e) {
          console.error(e);
          res.status(500).send(e.message);
        }
    });
};

注意:我不知道VisionAPI 是否像这样工作,但我使用了您正在使用的相同逻辑和参数。


推荐阅读