首页 > 解决方案 > Cloud Function annotateImage() 将“位置 1 的 JSON 中的意外标记 o”返回到本机 iOS 应用程序

问题描述

我正在使用 Firebase Cloud Functions 为原生 iOS 移动应用程序创建 ImageAnnotator,遵循iOS 客户端Cloud Function的 Firebase 文档。然而,在调用“annotateImage”客户端时,返回错误“位置 1 处 JSON 中的意外令牌 o”。我正在使用 XCode 13。

我的客户代码:

import Foundation
import Firebase
import Resolver

class ImageAnnotator: ObservableObject {
  @LazyInjected var functions: Functions
  @Published var annotatedText: String?
  @Published var error: NSError?

  func annotateImage(imageData: Data) {
    let base64encodedImage = imageData.base64EncodedString()

    let requestData = [
      "image": ["content": base64encodedImage],
      "features": ["type": "DOCUMENT_TEXT_DETECTION"],
      "imageContext": ["languageHints": ["en"]]
    ]

    functions.httpsCallable("annotateImage").call(requestData) { (result, error) in
      if let error = error as NSError? {
        self.error = error
        return
      }
      
      DispatchQueue.main.async {
        guard let annotation = (result?.data as? [String: Any])?["fullTextAnnotation"] as? [String: Any]
        else {
          return
        }
        print("%nComplete annotation:")
        let text = annotation["text"] as? String ?? ""
        print("%n\(text)")
        self.annotatedText = text
      }
    }
  }
}

我的 index.js 云函数代码:

const functions = require('firebase-functions');
const vision = require('@google-cloud/vision');
const client = new vision.ImageAnnotatorClient();
exports.annotateImage = functions.https.onCall(async (data, context) => {
  if (!context.auth) {
    throw new functions.https.HttpsError(
      "unauthenticated",
      "annotateImage must be called while authenticated."
    );
  }
  try {
    return await client.annotateImage(JSON.parse(data));
  } catch (e) {
    throw new functions.https.HttpsError("internal", e.message, e.details);
  }
});

什么可能导致此错误从 annotateImage() 调用返回?

标签: iosswiftfirebasegoogle-cloud-functionsgoogle-cloud-vision

解决方案


我能够通过使用此处建议的解决方案来解决错误:

  1. 将 requestData 的 'features' 字典值更改为数组。
  2. 将 requestData 作为编码字符串 JSON 传递给 annotateImage()。

但还是一线

guard let annotation = (result?.data as? [String: Any])?["fullTextAnnotation"] as? [String: Any]

返回零。

该行未正确解析结果对象。我通过将 result.data 串行向下转换为 NSArray,然后将 NSArray 的 0 索引到 NSDictionary 来解决 nil 返回。然后我能够以 [String: Any] 的形式访问 NSDictionary 的 fullAnnotatedText 字段。

完整代码:

import Foundation
import Firebase
import Resolver

class ImageAnnotator: ObservableObject {
  @LazyInjected var functions: Functions
  @Published var annotatedText: String?
  
  func annotateImage(imageData: Data) {

    struct requestData: Encodable {
      let image: [String: Data]
      let features = [["type": "DOCUMENT_TEXT_DETECTION"]]

      init(imageData: Data) {
        image = ["content": imageData]
      }
    }

    let encoder = JSONEncoder()

    let encodedData = try! encoder.encode(requestData(imageData: imageData))
    let string = String(data: encodedData, encoding: .utf8)!

    functions.httpsCallable("annotateImage").call(string) { (result, error) in
      if let error = error as NSError? {
        if error.domain == FunctionsErrorDomain {
          let code = FunctionsErrorCode(rawValue: error.code)
          let message = error.localizedDescription
          let details = error.userInfo[FunctionsErrorDetailsKey]
          print("ERROR \(String(describing: message)), CODE \(String(describing: code)), DETAILS \(String(describing: details))")
        }
        return
      }
      
      print("Success.")
      
      DispatchQueue.main.async {
        /* Parse result object */
        guard let nsarray = result?.data as? NSArray
        else {
          return
        }
        
        guard let nsdictionary = nsarray[0] as? NSDictionary
        else {
          return
        }

        guard let fullTextAnnotation = nsdictionary["fullTextAnnotation"] as? [String: Any]
        else {
          return
        }
        
        let text = fullTextAnnotation["text"] as? String ?? ""
        print("Recognized text: \(text)")
      }
    }
  }
}

推荐阅读