זיהוי טקסט בתמונות בצורה מאובטחת עם Cloud Vision באמצעות Firebase Auth ופונקציות בפלטפורמות Apple

כדי להתקשר ל-Google Cloud API מהאפליקציה שלך, עליך ליצור REST API ביניים שמטפל בהרשאה ומגן על ערכים סודיים כגון מפתחות API. לאחר מכן עליך לכתוב קוד באפליקציה לנייד שלך כדי לאמת ולתקשר עם שירות הביניים הזה.

אחת הדרכים ליצור REST API זה היא באמצעות Firebase Authentication and Functions, המעניק לך שער מנוהל ללא שרת אל ממשקי Google Cloud API שמטפל באימות וניתן להתקשר אליו מהאפליקציה לנייד שלך עם ערכות SDK מובנות מראש.

מדריך זה מדגים כיצד להשתמש בטכניקה זו כדי לקרוא ל-Cloud Vision API מהאפליקציה שלך. שיטה זו תאפשר לכל המשתמשים המאומתים לגשת לשירותי החיוב של Cloud Vision דרך פרויקט הענן שלך, אז שקול אם מנגנון אימות זה מספיק למקרה השימוש שלך לפני שתמשיך.

לפני שאתה מתחיל

הגדר את הפרויקט שלך

אם עדיין לא הוספת את Firebase לאפליקציה שלך, עשה זאת על ידי ביצוע השלבים במדריך לתחילת העבודה .

השתמש ב- Swift Package Manager כדי להתקין ולנהל תלות ב-Firebase.

  1. ב-Xcode, כשפרויקט האפליקציה שלך פתוח, נווט אל קובץ > הוסף חבילות .
  2. כשתתבקש, הוסף את מאגר Firebase Apple platforms SDK:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. בחר את ספריית Firebase ML.
  5. הוסף את הדגל -ObjC לקטע Other Linker Flags של הגדרות הבנייה של היעד שלך.
  6. בסיום, Xcode יתחיל באופן אוטומטי לפתור ולהוריד את התלות שלך ברקע.

לאחר מכן, בצע כמה הגדרות בתוך האפליקציה:

  1. באפליקציה שלך, ייבא את Firebase:

    מָהִיר

    import FirebaseMLModelDownloader

    Objective-C

    @import FirebaseMLModelDownloader;

עוד כמה שלבי תצורה, ואנחנו מוכנים לצאת לדרך:

  1. אם עדיין לא הפעלת ממשקי API מבוססי ענן עבור הפרויקט שלך, עשה זאת כעת:

    1. פתח את הדף Firebase ML APIs של מסוף Firebase.
    2. אם עדיין לא שדרגת את הפרויקט שלך לתוכנית התמחור של Blaze, לחץ על שדרג כדי לעשות זאת. (תתבקש לשדרג רק אם הפרויקט שלך אינו בתוכנית Blaze.)

      רק פרויקטים ברמת Blaze יכולים להשתמש בממשקי API מבוססי ענן.

    3. אם ממשקי API מבוססי ענן עדיין לא מופעלים, לחץ על הפעל ממשקי API מבוססי ענן .
  2. הגדר את מפתחות ה-API הקיימים של Firebase כדי לא לאפשר גישה ל-Cloud Vision API:
    1. פתח את דף האישורים של מסוף הענן.
    2. עבור כל מפתח API ברשימה, פתח את תצוגת העריכה ובקטע מגבלות מפתח, הוסף לרשימה את כל ממשקי ה-API הזמינים מלבד Cloud Vision API.

פרוס את הפונקציה הניתנת להתקשרות

לאחר מכן, פרוס את פונקציית הענן שבה תשתמש כדי לגשר בין האפליקציה שלך לבין Cloud Vision API. מאגר functions-samples מכיל דוגמה שתוכל להשתמש בה.

כברירת מחדל, גישה ל-Cloud Vision API באמצעות פונקציה זו תאפשר רק למשתמשים מאומתים של האפליקציה שלך גישה ל-Cloud Vision API. אתה יכול לשנות את הפונקציה לדרישות שונות.

כדי לפרוס את הפונקציה:

  1. שכפל או הורד את ה- functions-samples repo ושנה לספריית Node-1st-gen/vision-annotate-image :
    git clone https://github.com/firebase/functions-samples
    cd Node-1st-gen/vision-annotate-image
    
  2. תלות בהתקנה:
    cd functions
    npm install
    cd ..
    
  3. אם אין לך את Firebase CLI, התקן אותו .
  4. אתחול פרויקט Firebase בספריית vision-annotate-image . כאשר תתבקש, בחר את הפרויקט שלך ברשימה.
    firebase init
  5. פרוס את הפונקציה:
    firebase deploy --only functions:annotateImage

הוסף Firebase Auth לאפליקציה שלך

הפונקציה הניתנת להתקשרות שנפרסה למעלה תדחה כל בקשה ממשתמשים לא מאומתים של האפליקציה שלך. אם עדיין לא עשית זאת, תצטרך להוסיף Firebase Auth לאפליקציה שלך.

הוסף תלות נחוצה לאפליקציה שלך

השתמש ב- Swift Package Manager כדי להתקין את ספריית Cloud Functions for Firebase.

עכשיו אתה מוכן להתחיל לזהות טקסט בתמונות.

1. הכן את תמונת הקלט

כדי לקרוא ל-Cloud Vision, התמונה חייבת להיות בפורמט כמחרוזת מקודדת base64. כדי לעבד UIImage :

מָהִיר

guard let imageData = uiImage.jpegData(compressionQuality: 1.0) else { return }
let base64encodedImage = imageData.base64EncodedString()

Objective-C

NSData *imageData = UIImageJPEGRepresentation(uiImage, 1.0f);
NSString *base64encodedImage =
  [imageData base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];

2. הפעל את הפונקציה הניתנת להתקשרות כדי לזהות טקסט

כדי לזהות ציוני דרך בתמונה, הפעל את הפונקציה הניתנת להתקשרות המעביר בקשת JSON Cloud Vision .

  1. ראשית, אתחל מופע של פונקציות ענן:

    מָהִיר

    lazy var functions = Functions.functions()
    

    Objective-C

    @property(strong, nonatomic) FIRFunctions *functions;
    
  2. צור את הבקשה. ממשק ה-API של Cloud Vision תומך בשני סוגי זיהוי טקסט: TEXT_DETECTION ו- DOCUMENT_TEXT_DETECTION . עיין ב- Cloud Vision OCR Docs עבור ההבדל בין שני מקרי השימוש.

    מָהִיר

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

    Objective-C

    NSDictionary *requestData = @{
      @"image": @{@"content": base64encodedImage},
      @"features": @{@"type": @"TEXT_DETECTION"},
      @"imageContext": @{@"languageHints": @[@"en"]}
    };
    
  3. לבסוף, הפעל את הפונקציה:

    מָהִיר

    do {
      let result = try await functions.httpsCallable("annotateImage").call(requestData)
      print(result)
    } catch {
      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]
        }
        // ...
      }
    }
    

    Objective-C

    [[_functions HTTPSCallableWithName:@"annotateImage"]
                              callWithObject:requestData
                                  completion:^(FIRHTTPSCallableResult * _Nullable result, NSError * _Nullable error) {
            if (error) {
              if ([error.domain isEqualToString:@"com.firebase.functions"]) {
                FIRFunctionsErrorCode code = error.code;
                NSString *message = error.localizedDescription;
                NSObject *details = error.userInfo[@"details"];
              }
              // ...
            }
            // Function completed succesfully
            // Get information about labeled objects
    
          }];
    

3. חלץ טקסט מגושים של טקסט מוכר

אם פעולת זיהוי הטקסט תצליח, תגובת JSON של BatchAnnotateImagesResponse תוחזר בתוצאת המשימה. ניתן למצוא את הערות הטקסט באובייקט fullTextAnnotation .

אתה יכול לקבל את הטקסט המוכר כמחרוזת בשדה text . לדוגמה:

מָהִיר

let annotation = result.flatMap { $0.data as? [String: Any] }
    .flatMap { $0["fullTextAnnotation"] }
    .flatMap { $0 as? [String: Any] }
guard let annotation = annotation else { return }

if let text = annotation["text"] as? String {
  print("Complete annotation: \(text)")
}

Objective-C

NSDictionary *annotation = result.data[@"fullTextAnnotation"];
if (!annotation) { return; }
NSLog(@"\nComplete annotation:");
NSLog(@"\n%@", annotation[@"text"]);

אתה יכול גם לקבל מידע ספציפי לאזורים בתמונה. עבור כל block , paragraph , word symbol , ניתן לזהות את הטקסט באזור ואת הקואורדינטות התוחמות של האזור. לדוגמה:

מָהִיר

guard let pages = annotation["pages"] as? [[String: Any]] else { return }
for page in pages {
  var pageText = ""
  guard let blocks = page["blocks"] as? [[String: Any]] else { continue }
  for block in blocks {
    var blockText = ""
    guard let paragraphs = block["paragraphs"] as? [[String: Any]] else { continue }
    for paragraph in paragraphs {
      var paragraphText = ""
      guard let words = paragraph["words"] as? [[String: Any]] else { continue }
      for word in words {
        var wordText = ""
        guard let symbols = word["symbols"] as? [[String: Any]] else { continue }
        for symbol in symbols {
          let text = symbol["text"] as? String ?? ""
          let confidence = symbol["confidence"] as? Float ?? 0.0
          wordText += text
          print("Symbol text: \(text) (confidence: \(confidence)%n")
        }
        let confidence = word["confidence"] as? Float ?? 0.0
        print("Word text: \(wordText) (confidence: \(confidence)%n%n")
        let boundingBox = word["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
        print("Word bounding box: \(boundingBox.description)%n")
        paragraphText += wordText
      }
      print("%nParagraph: %n\(paragraphText)%n")
      let boundingBox = paragraph["boundingBox"] as? [Float] ?? [0.0, 0.0, 0.0, 0.0]
      print("Paragraph bounding box: \(boundingBox)%n")
      let confidence = paragraph["confidence"] as? Float ?? 0.0
      print("Paragraph Confidence: \(confidence)%n")
      blockText += paragraphText
    }
    pageText += blockText
  }
}

Objective-C

for (NSDictionary *page in annotation[@"pages"]) {
  NSMutableString *pageText = [NSMutableString new];
  for (NSDictionary *block in page[@"blocks"]) {
    NSMutableString *blockText = [NSMutableString new];
    for (NSDictionary *paragraph in block[@"paragraphs"]) {
      NSMutableString *paragraphText = [NSMutableString new];
      for (NSDictionary *word in paragraph[@"words"]) {
        NSMutableString *wordText = [NSMutableString new];
        for (NSDictionary *symbol in word[@"symbols"]) {
          NSString *text = symbol[@"text"];
          [wordText appendString:text];
          NSLog(@"Symbol text: %@ (confidence: %@\n", text, symbol[@"confidence"]);
        }
        NSLog(@"Word text: %@ (confidence: %@\n\n", wordText, word[@"confidence"]);
        NSLog(@"Word bounding box: %@\n", word[@"boundingBox"]);
        [paragraphText appendString:wordText];
      }
      NSLog(@"\nParagraph: \n%@\n", paragraphText);
      NSLog(@"Paragraph bounding box: %@\n", paragraph[@"boundingBox"]);
      NSLog(@"Paragraph Confidence: %@\n", paragraph[@"confidence"]);
      [blockText appendString:paragraphText];
    }
    [pageText appendString:blockText];
  }
}