I am using the package 'firebase_ml_vision' in my project to do OCR. I can read Latin based languages just fine, however, I want to read Chinese characters. I know that there are on the device and cloud-based versions of the text recognizer. However, I can't find out how to 'enable' the cloud-based version in my app. I have already activated cloud-based APIs in Firebase as seen in this image:
Activated cloud apis
The code that I currently use is:
void _initializeVision() async{
final File imageFile = File(imagePath);
final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(imageFile);
final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
final VisionText visionText = await textRecognizer.processImage(visionImage);
for(TextBlock blocks in visionText.blocks){
for(TextLine line in blocks.lines){
print(line.text);
}
}}
Image I try to read
Results:
I/flutter (10432): FamilyMart Collection
I/flutter (10432): 10
I/flutter (10432): Pocket facial tissue
I/flutter (10432): Without fluorescent virgin fber from wood puip
I/flutter (10432): pampers your skin
Can anyone explain to me how to use cloud text recognizer for Flutter?
Have the same problem, don't think cloud-OCR currently works with the ML-Package. I managed to make it work via a POST request.
Here is everything you need: Make Vision API request
// Upload Image to Firebase and get
// 1. DownloadUrl or
// 2. StorageBucket or
//
// 3. Convert Image to base64 with
// String base64Image = base64Encode(File(imagePath).readAsBytesSync());
// (does not work for me, if you use this way make sure your `body` is correct)
String body = """{
'requests': [
{
'image': {
'source': {
'imageUri': '$downloadUrl'
}
},
'features': [
{
'type': 'DOCUMENT_TEXT_DETECTION'
}
]
}
]
}""";
http.Response res = await http
.post(
"https://vision.googleapis.com/v1/images:annotate?key=$API_KEY",
body: body
);
print("${res.body}");
Related
I'm new to both Flutter and Firebase, so please bear with me.
I have a realtime database which stores (as of now) a list of products.
The addProduct, and updateProduct methods in my code are working fine. But for some reason, deleteProduct isn't. It's giving me a 404 error when I try to access the database through URL, even though the exact same URL is working for the updateProduct function.
Here is the code for updateProduct:
final _productIndex =
_items.indexWhere((element) => element.id == productId);
if (_productIndex >= 0) {
final url = Uri.parse(
"https://flutter-shop-app-f1b23-default-rtdb.firebaseio.com/products/$productId.json");
return http
.patch(url,
body: json.encode({
"title": newProduct.title,
"description": newProduct.description,
"imageUrl": newProduct.imageUrl,
"price": newProduct.price,
}))
.then((_) {
_items[_productIndex] = newProduct;
notifyListeners();
});
} else {
print("ERROR");
}
return Future(null);
}
And here is the code for deleteProduct:
Future<void> deleteProduct(String productId) {
print(productId);
final url = Uri.parse(
"https://flutter-sdhop-app-f1b23-default-rtdb.firebaseio.com/products/$productId.json");
print(url.toString());
return http.delete(url).then((response) {
print(response.statusCode);
print(response.body);
if (response.statusCode >= 400) {
throw HttpException("Could not delete!");
}
_items.removeWhere((element) => element.id == productId);
notifyListeners();
});
}
And this is the (printed) error message :
I/flutter ( 5104): 404
I/flutter ( 5104): {
I/flutter ( 5104): "error" : "404 Not Found"
I/flutter ( 5104): }
I tried opening the URL in my browser window, and got the same 404 error, which was puzzling since Flutter seems to be able to access it for updating without any issues. The firebase project was created in test mode, so I don't think authentication will be the issue here.
Please help on how to fix this.
Here are the database rules:
{
"rules": {
".read": "now < 1624300200000", // 2021-6-22
".write": "now < 1624300200000", // 2021-6-22
}
}
To be honest I would not recommend that solution for you. The REST API is made for use cases where there is no native SDK. Flutter has definitely a very good one you can use. If you continue with that approach you would have the double work because you can't reause anything you made with the REST API. And also the BEST stuff in Firebase like realtime listeners is not in the REST API. Authentication is a hustle with the REST API. It's only a Plan B solution when there is no native SDK.
In the link for deletion you have a typo:
https://flutter-sdhop-app-f1b23-default-rtdb.firebaseio.com/products/
It should be shop and not sdhp.
I have a problem with Firebase. I learned flutter using a video on youtube about how to delete data and images from firebase. And I have one function that deletes the image from firestore but I cannot use getReferenceFromUrl(). It shows the error
The method 'getReferenceFromUrl' isn't defined for the type 'FirebaseStorage'.
deleteFood(Food food, Function foodDeleted) async {
if (food.image != null) {
Reference storageReference =
await FirebaseStorage.instance.getReferenceFromUrl(food.image);
print(storageReference.path);
await storageReference.delete();
print('image deleted');
}
await FirebaseFirestore.instance.collection('Foods').doc(food.id).delete();
foodDeleted(food);
}
The getReferenceFromUrl is depracated as you can see here.
You would need to call ref() with the path to the file in the storage.
As #puff mentioned in the comment the new API call would be refFromURL('your_download_url')
As I know Firebase on Flutter will automatically read from cache first but I noticed while development that an app just play around with almost 1 stream that has 10 or 15 document I have reach reads above 4000 reads! By this way if 10 users has used my app I will pay all I have, so I have recheck every query, snapshot and put this code to know
print(itemDoc.metadata.isFromCache ? "itemDoc NOT FROM NETWORK" : "itemDoc FROM NETWORK");
Edit write the code and more explain
I noticed this issue appear in IOS when I update,add,delete a document console print all stored documents.
I have Main Stream that I get all users lists
then every list I create stream for it to listen list's items
userListsStream(uid){
Stream<QuerySnapshot> shoppingListsStream =
Firestore.instance.collection('lists').where('owner', arrayContains: uid).snapshots();
shoppingListsStream.listen(
(QuerySnapshot listsQuery) async {
List<DocumentSnapshot> listsDocs = listsQuery.documents;
if (listsDocs.length != 0) {
//? foreach on lists Documents
listsDocs.forEach(
(DocumentSnapshot listDoc) async {
print(listDoc.metadata.isFromCache ? "listDoc NOT FROM
NETWORK" : "listDoc FROM NETWORK");
listItemsStream(listDoc.documentID);
}
)
}
})
}
listItemsStream(lid){
shoppingItemsRef = Firestore.instance.collection('lists').document(lid).collection('items');
shoppingItemsRef.snapshots().listen(
(QuerySnapshot itemsQuery) async {
List<DocumentSnapshot> itemsDocs = itemsQuery.documents;
if (itemsDocs.length != 0) {
itemsDocs.forEach(
(DocumentSnapshot itemDoc) async {
print(itemDoc.metadata.isFromCache ? "itemDoc NOT FROM
NETWORK" : "itemDoc FROM NETWORK");
}
)
}
}
those two methods in Provider that I call the main function in Home.dart initState
#override
void initState() {
Provider.of<ListsProvider>(context, listen: false)
.userListsStream(uid);
}
The isFromCache flag indicates whether the document is guaranteed to be up to date with the server, or that it may be a stale result from the cache. If it's false that doesn't necessarily means the document was read from the server, but that you can be guaranteed that the document is up to date with the server.
To show what this means, I can this snippet
var snapshotsStream = Firestore.instance.collection("chat").orderBy("timestamp", descending: true).limit(3).snapshots();
snapshotsStream.listen((querySnapshot) {
print("We got a new QuerySnapshot");
querySnapshot.documents.forEach((doc) {
print(doc.documentID+": "+(doc.metadata.isFromCache ? "from CACHE " : "from SERVER "));
});
querySnapshot.documentChanges.forEach((docChange) {
print(docChange.type.toString()+(docChange.document.metadata.isFromCache ? "doc from CACHE " : "doc from SERVER "));
});
}, onError: (error) {
print(error);
});
The output I get initially is:
flutter: We got a new QuerySnapshot
flutter: 5nAr5pYgwXJ0n3pWZkLw: from SERVER
flutter: moysGY7Ea7TCf28fcEVC: from SERVER
flutter: PuNnPaiLMIE7704R9NuL: from SERVER
flutter: 5nAr5pYgwXJ0n3pWZkLw: DocumentChangeType.addeddoc from SERVER
flutter: moysGY7Ea7TCf28fcEVC: DocumentChangeType.addeddoc from SERVER
flutter: PuNnPaiLMIE7704R9NuL: DocumentChangeType.addeddoc from SERVER
Then when I make a change on the server, it prints:
flutter: We got a new QuerySnapshot
flutter: 5nAr5pYgwXJ0n3pWZkLw: from SERVER
flutter: moysGY7Ea7TCf28fcEVC: from SERVER
flutter: PuNnPaiLMIE7704R9NuL: from SERVER
flutter: 5nAr5pYgwXJ0n3pWZkLw: DocumentChangeType.modifieddoc from SERVER
So using the isFromCache property is not meant to determine whether the document was a charged read on the server, but whether the document is guaranteed to be up to date with the server.
To know what documents have changed, you can iterate over the documentChanged collection, as shown in the code above.
As to having more reads than you expected, one of the more common causes of this is keeping Firestore panel open in the Firebase console. Reads performed by the console are charged towards your project. For more on this, see:
Google Cloud Firestore console reading of all documents and charges
Firestore collection listeners enormous number of reads
Firestore - unexpected reads
edit: it is supposed to look like it does on the device log, according to Firebase support
I am adding push notifications via FCM to my Flutter app, but the message format is very different on the iOS Simulator vs. my iPhone 5s.
When receiving a push notification from the Firebase console to an active/opened app.
Problem: What do I need to do to make sure the real device receives the message in the correct format?
Log from Simulator (iPhone XR, 12.2) (looks like in the official code examples):
onMessage: {
from: 123000000000,
collapse_key: com.mydomainnamehere,
notification: {
body: Lorem ipsum,
title: Title,
e: 1,
tag: campaign_collapse_key_9876543210011223344
}
}
Log from real device (iPhone 5s, 12.2) (can't find any references online to this):
onMessage: {
google.c.a.c_l: notif_name,
google.c.a.e: 1,
aps: {
alert: {
title: Title,
body: Lorem ipsum
}
},
gcm.n.e: 1,
google.c.a.c_id: 9876543210011223344,
google.c.a.udt: 0,
gcm.message_id: 1234567800998877,
google.c.a.ts: 1234567800
}
The notification is sent from the Firebase console to all devices, the logs are taken from the same notification (but I anonymized the id's).
The Device and Simulator is running the same Flutter code from Android Studio, at the same time.
Parts of my pubspec.yaml that refers to FCM
firebase_core: ^0.4.0+1
firebase_auth: 0.11.1
cloud_firestore: ^0.11.0+2
firestore_ui: ^1.4.0
firebase_messaging: ^5.0.2
Software and SDK Versions
Flutter Channel dev, v1.8.4,
Mac OS X 10.14.5,
Android SDK version 28.0.3,
Xcode 10.2.1,
Android Studio version 3.4
Flutter message-handling code
void initState() {
super.initState();
if (Platform.isIOS) {
iosSubscription = _fcm.onIosSettingsRegistered.listen((IosNotificationSettings settings) {
print("FCM settings received: $settings");
});
_fcm.requestNotificationPermissions(IosNotificationSettings());
}
_fcm.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
},
);
getFcmToken();
}
void getFcmToken() async {
var token = await FirebaseMessaging().getToken();
print("Token $token");
}
I was expecting that the JSON format would be the same on both the simulator and a real device. But the real device isn't even receiving all of the notification.
According to Firebase support, we should not be able to get push notifications in the simulator, and they say that the gcm-format above is indeed the correct one.
The solution is to always use key-value pairs as stated in the answer to this previous question FCM - Get Message Label
For those who still struggle with this, there seems an alternative solution.
While the structure of the data can be different in various conditions (iOS/Android or Real device/Simulator), the key names of those essential parts of the data are considered to be unique no matter how deeply nested: "title" and "body". Therefore, extracting the values of those 'title' and 'body' entries might solve the problem.
//get title value from the message load (whether data or push)
String _title = _findFirstKeyValue(message, 'title');
The following is a recursive function to get the first matching entry from the message Map.
String _findFirstKeyValue(Map data, String targetKey) {
for (final k in data.keys) {
final v = data[k];
if (v is Map) { // go deeper if the value is still a kind of Map
final String _temp = _findFirstKeyValue(v, targetKey);
if (_temp != '') return _temp;
} else { // when the value is primitive Key-Value pair
if (k.toString().toLowerCase() == targetKey.toLowerCase()) {
return v.toString();
}
}
}
return '';
}
Note that return will not be fired if you use data.forEach rather than ordinary for loop.
I have been searching all over on how to implement firebase functions with a flutter application. It does not seem like there is an SDK available (yet). I've also tried adding the gradle dependency implementation 'com.google.firebase:firebase-functions:15.0.0' to my app/build.gradle but this causes build errors.
Has anyone done an implementation that works? I am unable to find any documentation on how to handle credentials and the transport of data in order to build my own firebase functions call.
I have created a rough outline of how I am thinking this is intended to work, but may be way off base.
Future<dynamic> updateProfile(String uid, AccountMasterViewModel avm) async {
Uri uri = Uri.parse(finalizeProfileFunctionURL);
var httpClient = new HttpClient();
String _result = '';
try {
return await httpClient
.postUrl(uri)
.then((HttpClientRequest request) {
return request.close();
// authentication??
// Fields and data??
})
.then((HttpClientResponse response) async {
print(response.transform(new Utf8Codec().decoder).join());
if (response.statusCode == HttpStatus.OK) {
String json = await response.transform(new Utf8Codec().decoder).join();
_result = jsonDecode(json);
// Do some work
return json;
}
else {
return ':\nHttp status ${response.statusCode}';
}
});
}
catch (exception) {
return 'Failed ' + exception.toString();
}
}
I'd like to be able to send an object, like
{
accountID: src.accountID,
accountName: src.name,
accountImg: src.image
}
and then handle the response. But as I said, I can't find any working examples or tutorials on how to do this. It's fairly simple to do this client size and talk directly to the database, however, there are validations and data components that need to be hidden from the client, so cloud functions is the way I would like to do this.
Yes, there is a cloud_function package available here: https://pub.dartlang.org/packages/cloud_function.
so as to make a call to the function you can just call
CloudFunctions.instance.call(
functionName: 'yourCloudFunction',
parameters: <String, dynamic>{
'param1': 'this is just a test',
'param2': 'hi there',
},
);
An updated answer to calling Firebase's Cloud Functions in Flutter would be
var callable = CloudFunctions.instance.getHttpsCallable(functionName: 'functionName'); // replace 'functionName' with the name of your function
dynamic response = callable.call(<String, dynamic>{
'param1': param1 //replace param1 with the name of the parameter in the Cloud Function and the value you want to insert
}).catchError((onError) {
//Handle your error here if the function failed
});
This is a good tutorial on cloud functions in flutter which helped me:
https://rominirani.com/tutorial-flutter-app-powered-by-google-cloud-functions-3eab0df5f957
Cloud functions can be triggered by data change triggers in the realtime database, Firestore, or Datastore, as well as authentication triggers.
You could just persist
{
accountID: src.accountID,
accountName: src.name,
accountImg: src.image
}
to the database and register a trigger that runs a Cloud Function when data at a specific path is inserted, updated, or deleted.
https://firebase.google.com/docs/functions/firestore-events