כדי לקרוא ל-Cloud APIs מהאפליקציה, צריך ליצור API בארכיטקטורת REST ביניים שמטפל בהרשאות ומגן על ערכים סודיים כמו מפתחות API. לאחר מכן צריך לכתוב קוד באפליקציה לנייד כדי לבצע אימות ולתקשר עם שירות הביניים הזה.
אחת הדרכים ליצור את REST API היא באמצעות Firebase Authentication ו-Functions. כך מקבלים שער מנוהל ללא שרת (serverless) ל-Google Cloud APIs שמטפל באימות, ואפשר להפעיל אותו מהאפליקציה לנייד באמצעות ערכות SDK מוכנות מראש.
במדריך הזה מוסבר איך להשתמש בשיטה הזו כדי לבצע קריאה ל-Cloud Vision API מהאפליקציה שלכם. השיטה הזו מאפשרת לכל המשתמשים המאומתים לגשת לשירותים בתשלום של Cloud Vision דרך פרויקט בענן שלכם, לכן כדאי לשקול אם מנגנון ההרשאה הזה מספיק לתרחיש השימוש שלכם לפני שממשיכים.
לפני שמתחילים
הגדרת הפרויקט
אם עדיין לא הוספתם את Firebase לאפליקציה, אתם צריכים לעשות זאת לפי השלבים שמפורטים במדריך לתחילת העבודה.משתמשים ב-Swift Package Manager כדי להתקין ולנהל יחסי תלות ב-Firebase.
- ב-Xcode, כשפרויקט האפליקציה פתוח, עוברים אל File > Add Packages (קובץ > הוספת חבילות).
- כשמוצגת בקשה, מוסיפים את מאגר Firebase Apple platforms SDK:
- בוחרים בספרייה Firebase ML.
- מוסיפים את הדגל
-ObjCלקטע Other Linker Flags בהגדרות הבנייה של יעד הקישור. - אחרי שתסיימו, פלטפורמת Xcode תתחיל לטפל ביחסי התלות ולהוריד אותם ברקע באופן אוטומטי.
https://github.com/firebase/firebase-ios-sdk.git
עכשיו מבצעים הגדרה באפליקציה:
- באפליקציה, מייבאים את Firebase:
Swift
import FirebaseMLModelDownloader
Objective-C
@import FirebaseMLModelDownloader;
עוד כמה שלבי הגדרה, והכול יהיה מוכן:
-
אם עדיין לא הפעלתם ממשקי API מבוססי-Cloud בפרויקט, עכשיו זה הזמן:
- פותחים את הדף Firebase ML APIs במסוף Firebase.
-
אם עדיין לא שדרגתם את הפרויקט לתוכנית התמחור Blaze בתשלום לפי שימוש, אתם צריכים ללחוץ על שדרוג. (תתבקשו לשדרג רק אם הפרויקט שלכם לא נמצא בתוכנית התמחור Blaze).
רק פרויקטים במינוי Blaze בתשלום לפי שימוש יכולים להשתמש בממשקי API מבוססי-Cloud.
- אם ממשקי API מבוססי-ענן עדיין לא הופעלו, לוחצים על הפעלת ממשקי API מבוססי-ענן.
- מגדירים את מפתחות ה-API הקיימים ב-Firebase כך שלא תהיה להם גישה ל-Cloud Vision API:
- פותחים את הדף Credentials במסוף Cloud.
- לכל מפתח API ברשימה, פותחים את תצוגת העריכה, ובקטע Key Restrictions מוסיפים לרשימה את כל ממשקי ה-API הזמינים חוץ מ-Cloud Vision API.
פריסת הפונקציה שאפשר לקרוא לה
בשלב הבא, פורסים את פונקציית Cloud Functions שבה ישתמשו כדי לגשר בין האפליקציה לבין Cloud Vision API. מאגר functions-samples מכיל דוגמה שאפשר להשתמש בה.
כברירת מחדל, גישה ל-Cloud Vision API דרך הפונקציה הזו תאפשר רק למשתמשים מאומתים של האפליקציה שלכם לגשת ל-Cloud Vision API. אפשר לשנות את הפונקציה בהתאם לדרישות שונות.
כדי לפרוס את הפונקציה:
- משכפלים או מורידים את המאגר functions-samples
ועוברים לספרייה
Node-1st-gen/vision-annotate-image:git clone https://github.com/firebase/functions-samplescd Node-1st-gen/vision-annotate-image - יחסי תלות של התקנות:
cd functionsnpm installcd .. - אם לא מותקן Firebase CLI, מתקינים אותו.
- מאתחלים פרויקט Firebase בספרייה
vision-annotate-image. כשמופיעה בקשה, בוחרים את הפרויקט מהרשימה.firebase init
- פורסים את הפונקציה:
firebase deploy --only functions:annotateImage
הוספת Firebase Auth לאפליקציה
הפונקציה שאפשר להפעיל מרחוק שפורסמה למעלה תדחה כל בקשה ממשתמשים לא מאומתים באפליקציה. אם עדיין לא עשיתם זאת, תצטרכו להוסיף את Firebase Auth לאפליקציה.
הוספת יחסי תלות נדרשים לאפליקציה
משתמשים ב-Swift Package Manager כדי להתקין את ספריית Cloud Functions for Firebase.
עכשיו אפשר להתחיל לזהות טקסט בתמונות.
1. הכנת תמונת הקלט
כדי להתקשר אל Cloud Vision, התמונה צריכה להיות בפורמט של מחרוזת בקידוד Base64. כדי לעבדUIImage:
Swift
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.קודם, מאתחלים מופע של Cloud Functions:
Swift
lazy var functions = Functions.functions()Objective-C
@property(strong, nonatomic) FIRFunctions *functions;יוצרים את הבקשה. Cloud Vision API תומך בשני סוגים של זיהוי טקסט:
TEXT_DETECTIONו-DOCUMENT_TEXT_DETECTION. ההבדל בין שני תרחישי השימוש מוסבר במסמכי ה-OCR של Cloud Vision.Swift
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"]} };לבסוף, מפעילים את הפונקציה:
Swift
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. לדוגמה:
Swift
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, אפשר לקבל את הטקסט שזוהה באזור ואת קואורדינטות התיחום של האזור. לדוגמה:
Swift
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];
}
}