To get help from the community, we encourage using Stack Overflow and the tensorflow.js tag.
"@react-native-community/async-storage": "^1.6.1",
"@tensorflow/tfjs": "^1.2.8",
"@tensorflow/tfjs-react-native": "0.1.0-alpha.2",
"expo-gl": "^6.0.0",
"expo-gl-cpp": "^6.0.0",
"react": "16.8.3",
"react-native": "0.59.10",
"react-native-unimodules": "^0.7.0-rc.1",
"typescript": "^3.6.3"
react-native app
When I am trying to use the "bundleResourceio" function to load mdoel from local mobile device, Yellowbox occurs with following mention:

It is triggered by click on the buttom.
In the console, it shows:

From my understanding it is probably some require cycle between tfjs-react-native customised fetch and react-native fetch functions which causes the undefined fetch function?
But it is hard to debug and where to modified, I even tried use the demo ts file here, still got this error...
Any ideas?
The react-native app consists:

import React, { Component } from "react";
import * as tf from '@tensorflow/tfjs';
import { bundleResourceIO} from '@tensorflow/tfjs-react-native';
import { View, Text, Button } from 'react-native';
const modelJson = require('./assets/model.json');
const modelWeights = require('./assets/group1-shard1of1.bin');
const BACKEND_CONFIG = 'cpu';
export default class App extends Component {
constructor(prop){
super(prop);
this.state = {
isModelReady: false,
useModel: {}
};
};
async componentDidMount() {
await tf.setBackend(BACKEND_CONFIG);
await tf.ready();
// Signal to the app that tensorflow.js can now be used.
console.log("componentDidMount: tf.ready is set");
console.log("the MyModelLoadLocal component is mounted");
}
OnPressLoadLocalModel = async () =>{
console.log("model loading button is pressed...");
console.log(" start load local model");
const beginModelLoadTs = new Date().getTime();
const model = await tf.loadGraphModel(bundleResourceIO(modelJson, modelWeights));
const endModelLoadTs = new Date().getTime();
console.log("mili sec for model loading: " + (endModelLoadTs - beginModelLoadTs));
console.log("local model loading is done: " + model);
this.setState({
useModel: model,
isModelReady: true
});
}
render() {
return (
<View>
<Text>
hello world
</Text>
<Text>
current use model state: {this.state.isModelReady.toString()}
</Text>
<Button
title="Load model"
color="#f194ff"
onPress={ this.OnPressLoadLocalModel }
/>
</View>
);
}
}
If you would like to get help from the community, we encourage using Stack Overflow and the tensorflow.js tag.
GitHub issues for this repository are tracked in the tfjs union repository.
Please file your issue there, following the guidance in that issue template.
@gitathrun is it same with latest tfjs version as well ?
@gitathrun I'll take a look, two questions, could you check that the values for modelJson and modelWeights are what you expect. If you console.log/console.warn them you should see a json structure for the first one that corresponds to the file and for the second one you should see a number. Could you confirm that it is what you expect.
Also just confirming that you modified your metro config to allow the resolver to resolve .bin files assetExts: ['bin', 'txt', 'jpg'], (See https://github.com/tensorflow/tfjs/tree/master/tfjs-react-native#step-3-configure-metro)
@rthadur I did not test with the latest tfjs version, because I try to keep the same dependencies version with the tfjs-react-native demo.
@tafsiri I have update the code in App.js listed below, and the console result, All the key, value in modelJson can be fetched correctly, and the modelWeights is a Number with 1.
App.js
import React, { Component } from "react";
import * as tf from '@tensorflow/tfjs';
import { bundleResourceIO} from '@tensorflow/tfjs-react-native';
import { View, Text, Button } from 'react-native';
const modelJson = require('./assets/model.json');
const modelWeights = require('./assets/group1-shard1of1.bin');
const BACKEND_CONFIG = 'cpu';
export default class App extends Component {
constructor(prop){
super(prop);
this.state = {
isModelReady: false,
useModel: {}
};
};
async componentDidMount() {
await tf.setBackend(BACKEND_CONFIG);
await tf.ready();
// Signal to the app that tensorflow.js can now be used.
console.log("componentDidMount: tf.ready is set");
//print out model.json and modelWeights
console.log("modelWeights: " + modelWeights);
console.log("modelJson: "+modelJson);
Object.keys(modelJson).forEach(function (item) {
console.log(item); // key
console.log(modelJson[item]); // value
});
console.log("the MyModelLoadLocal component is mounted");
}
OnPressLoadLocalModel = async () =>{
console.log("model loading button is pressed...");
console.log("in MyConcatUSEModel.localModelLoader: start load local model");
const beginModelLoadTs = new Date().getTime();
const usemodelEncoder = await tf.loadGraphModel(bundleResourceIO(modelJson, modelWeights));
const endModelLoadTs = new Date().getTime();
console.log("mili sec for model loading: " + (endModelLoadTs - beginModelLoadTs));
console.log("local model loading is done: " + usemodelEncoder);
this.setState({
useModel: usemodelEncoder,
isUSEReady: true
});
}
render() {
return (
<View>
<Text>
hello world.
</Text>
<Text>
current use model state: {this.state.isModelReady.toString()}
</Text>
<Button
title="Load model"
color="#f194ff"
onPress={ this.OnPressLoadLocalModel }
/>
</View>
);
}
}
results in console.log

The metro config is exactly the same as Step 3, here is mine:
/**
* Metro configuration for React Native
* https://github.com/facebook/react-native
*
* @format
*/
// Change 1 (import the blacklist utility)
const blacklist = require('metro-config/src/defaults/blacklist');
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
resolver: {
// Change 2 (add 'bin' to assetExts)
assetExts: ['bin', 'txt', 'jpg'],
sourceExts: ['js', 'json', 'ts', 'tsx', 'jsx'],
// Change 3 (add platform_node to blacklist)
blacklistRE: blacklist([/platform_node/])
},
};
@tafsiri Hello, any progress on this topic?
@tafsiri Hello, I have tried with the same configuration but react-native version 0.60.
The result is the same, caused by require cycle of fetch:

Hi @gitathrun sorry for the delay in looking into this. I tried to reproduce this but was unable to do so exactly.
In debug mode, I don't get the require cycle warning related to fetch.
To help debug I created a branch https://github.com/tensorflow/tfjs/tree/2177-bundleResourceIO where the integration app has a new diagnostic test that loads a graphModel from the bundle.
With a release build I do have an issue, but that may have more to do with the android build settings, i'm going to continue to look into this but I'm not sure if it's the same as your issue.
To narrow this down:

Hi, @tafsiri , thanks for the reply.
To your questions:
Is it possible that you have another dependency loading a fetch library/polyfill? Could you post your package.json?
My package.json
{
"name": "tfjs_rn_demo_59",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"@react-native-community/async-storage": "^1.6.1",
"@tensorflow-models/mobilenet": "^2.0.4",
"@tensorflow/tfjs": "^1.2.8",
"@tensorflow/tfjs-react-native": "0.1.0-alpha.2",
"expo-gl": "^6.0.0",
"expo-gl-cpp": "^6.0.0",
"node-nlp-rn": "^3.5.2",
"react": "16.8.3",
"react-native": "0.59.10",
"react-native-unimodules": "^0.7.0-rc.1",
"typescript": "^3.6.3"
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/runtime": "^7.5.5",
"babel-jest": "^24.8.0",
"jest": "^24.8.0",
"metro-react-native-babel-preset": "^0.55.0",
"react-test-renderer": "16.8.3"
},
"jest": {
"preset": "react-native"
}
}
Might be the "@tensorflow-models/mobilenet": "^2.0.4", got us into the issue? Since it do requie the developer to access internet and fetch the mobilenet model+weight from google storage?
Are you running into this with a debug or release build? (given the messages above I assumed debug mode).
Firstly, I do try to get it working in debug mode, not working, then I try to build a release apk, but with another problem, which is
> Task :app:mergeReleaseResources FAILED
[raw/group1shard1of1] /app/tfjs/tfjs_rn/tfjs_rn_demo_60/android/app/src/main/res/raw/group1shard1of1.bin [raw/group1shard1of1] /app/tfjs/tfjs_rn/tfjs_rn_demo_60/android/app/build/generated/res/react/release/raw/group1shard1of1.bin: Error: Duplicate resources
This the error shows in rn 60 version, but this error also shows up in rn 59 version.
Are you able to run the integration_rn59 from the branch linked above app locally, do you get a similar result? I've included a screenshot below of what I am getting when i click the 'show diagnostic screen' button.
I will get the result back to you asap.
hi, @tafsiri negative, I cant get the demo running, I got issues in bundle process:

Thanks for the info, i've dug into this a bit more and was able to reproduce some of your errors.
"@tensorflow/tfjs": "1.2.11". Note that there is no ^ as you need that exact version, that is the most recent version that is compatible with the current release of tfjs-react-native, this should fix the network request issue.If that does not work
blacklistRE setting in metro.config.js to look likeblacklistRE: blacklist([/platform_node/, /@tensorflow.*_test.js/]) (note the addition of /@tensorflow.*_test.js/npx react-native run-android. I'm curious to see if there is different behavior than when using your custom build command.This should get things running in debug mode. However through this I have discovered an issue when running this in release mode which will take a new release in order to fix. I'll post an update here when I work out a fix. If you still have have issues in debug mode, let me know.
Hi, @tafsiri
I have tried the solutions you provide, it works but:

3, It only works in debug mode as you indicates. I have successfully create the bundle for Release, signed, install it on devices, checked in Android Studio make sure all files (the model files as well) included, but the "Network fetch error" still ocurred. So the app could not load model from a relased apk. This applies to both rn 0.59 and 0.60. I am wandering is it the "paths" parameters in model.json is not compat with bundled model weight file, because the .bin file name is changed during the bundle process?
PS: is it possible to use tf.loadLayersModel() with an URL links to fetch the model from a cloud ? (Azure blob, for example) in tfjs-react-native? It seems from the mobilenet package code that the model from Google's open storage is fetched by using loadGraphModel() from tf.converter, not from tf.
Many thanks.
I have the same issue and keep track of discussion!
@gitathrun
loadLayersModel with a url to fetch a model hosted on the web. This is how mobilenet works. loadLayersModel and loadGraphModel are functionally equivalent, but they load different kinds of models. @tafsiri

Yep the issue in release mode is due to renaming/moving resources in the bundling process causing the resolved path from RNs resolver to be incorrect. (note the path in the json doesn't matter).
Good, which means it is a RN resolver problem. I try to manually change the paths property in model.json into the file name shows in release apk, but it does not work.
Thanks for the info about the unimodules upgrade, I'll take a look at that after working out the .bin resolution issue.
That is my guess, since this is the only difference between 59 and 60. Other configurations such as app.js, model.json, etc are identical.
Yes you can use loadLayersModel with a url to fetch a model hosted on the web. This is how mobilenet works. loadLayersModel and loadGraphModel are functionally equivalent, but they load different kinds of models.
That is great, mobilenet code, although it is loadGraphModel, but I think it can be changed to loadLayersModel.
Update: works for Azure Blob storage, but Blob container has to be public for model.json access.
@gitathrun Just did a new release that should fix this issue. Try https://www.npmjs.com/package/@tensorflow/tfjs-react-native/v/0.1.0-alpha.3 and let me know if it solves the problem.
This version does need the latest version (1.3.x) of tfjs.
Hi, @tafsiri
Sorry for the late reply, I do spend sometime to re-create project and test the new verision, here is what I got:
I can confirm it works as expected in react-native version @0.59.x.
But unfortunately, it could not work with react-native version >[email protected].
With the rn version higher than 0.60.x, it can successfuly bundle, and installed to device, but when click the app, the app just flash crashed, without following errors shows in the log:
11-29 09:07:58.917 3656 3656 I MicroDetectionWorker: onReady
11-29 09:07:58.927 3656 6671 I MicroRecognitionRunner: Starting detection.
11-29 09:07:58.927 3656 6667 I MicrophoneInputStream: mic_starting SR : 16000 CC : 16 SO : 6
11-29 09:07:58.928 1598 1656 E : Request requires android.permission.RECORD_AUDIO
11-29 09:07:58.928 1598 1656 E AudioPolicyIntefaceImpl: getInputForAttr permission denied: recording not allowed for uid 10034 pid 3656
11-29 09:07:58.928 1598 1656 E AudioFlinger: createRecord() checkRecordThread_l failed
11-29 09:07:58.928 3656 6667 E IAudioFlinger: createRecord returned error -22
11-29 09:07:58.928 3656 6667 E AudioRecord: AudioFlinger could not create record track, status: -22
11-29 09:07:58.928 3656 6667 E AudioRecord-JNI: Error creating AudioRecord instance: initialization check failed with status -22.
11-29 09:07:58.928 3656 6667 E android.media.AudioRecord: Error code -20 when initializing native AudioRecord object.
11-29 09:07:58.928 3656 6667 I MicrophoneInputStream: mic_started SR : 16000 CC : 16 SO : 6
11-29 09:07:58.929 3656 6667 E ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded
11-29 09:07:58.929 3656 3656 I MicroDetectionWorker: onReady
11-29 09:07:58.930 3656 6667 I MicrophoneInputStream: mic_close SR : 16000 CC : 16 SO : 6
11-29 09:07:58.930 3656 6671 I MicroRecognitionRunner: Detection finished
11-29 09:07:58.930 3656 6671 W ErrorReporter: reportError [type: 211, code: 524300]: Error reading from input stream
11-29 09:07:58.931 3656 3930 I MicroRecognitionRunner: Stopping hotword detection.
11-29 09:07:58.931 3656 6671 W ErrorProcessor: onFatalError, processing error from engine(4)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: com.google.android.apps.gsa.shared.speech.b.g: Error reading from input stream
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.staticplugins.microdetection.d.k.a(SourceFile:91)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.staticplugins.microdetection.d.l.run(Unknown Source:14)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.libraries.gsa.runner.a.a.b(SourceFile:32)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.libraries.gsa.runner.a.c.call(Unknown Source:4)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.shared.util.concurrent.b.g.run(Unknown Source:4)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.shared.util.concurrent.b.aw.run(SourceFile:4)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.shared.util.concurrent.b.aw.run(SourceFile:4)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at java.lang.Thread.run(Thread.java:764)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.shared.util.concurrent.b.i.run(SourceFile:6)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: Caused by: com.google.android.apps.gsa.shared.exception.GsaIOException: Error code: 393238 | Buffer overflow, no available space.
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.speech.audio.Tee.j(SourceFile:103)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.speech.audio.au.read(SourceFile:2)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at java.io.InputStream.read(InputStream.java:101)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.speech.audio.ao.run(SourceFile:17)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at com.google.android.apps.gsa.speech.audio.an.run(SourceFile:2)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
11-29 09:07:58.931 3656 6671 W ErrorProcessor: ... 10 more
11-29 09:07:58.931 3656 6671 I AudioController: internalShutdown
11-29 09:07:58.932 3656 3656 I MicroDetector: Keeping mic open: false
11-29 09:07:58.932 3656 6672 I DeviceStateChecker: DeviceStateChecker cancelled
11-29 09:07:58.932 3656 3656 I MicroDetectionWorker: #onError(false)
11-29 09:07:59.010 7368 7387 D EGL_emulation: eglMakeCurrent: 0xec9dde20: ver 2 0 (tinfo 0xec96bbf0)
11-29 09:07:59.018 1756 2382 D gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
11-29 09:07:59.018 1756 2382 D : HostConnection::get() New Host Connection established 0xeac5a0c0, tid 2382
11-29 09:07:59.023 1756 2382 D gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
11-29 09:07:59.024 1756 2382 D : HostConnection::get() New Host Connection established 0xeac552c0, tid 2382
11-29 09:07:59.025 1756 2382 D gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
11-29 09:07:59.025 1756 2382 D : HostConnection::get() New Host Connection established 0xeac552c0, tid 2382
11-29 09:07:59.025 1756 2382 D gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
11-29 09:07:59.039 1756 2382 W SurfaceFlinger: Attempting to destroy on removed layer: AppWindowToken{a50cb31 token=Token{d46cbd8 ActivityRecord{59d5abb u0 com.verify_simplebundledemo_60/.MainActivity t16}}}#0
11-29 09:07:59.093 1868 1868 E netmgr : Failed to open QEMU pipe 'qemud:network': Invalid argument
11-29 09:07:59.093 1868 1868 E netmgr : WifiForwarder unable to open QEMU pipe: Invalid argument
11-29 09:07:59.229 1923 2276 I GnssLocationProvider: WakeLock acquired by sendMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@ce8e03)
11-29 09:07:59.229 1923 1941 I GnssLocationProvider: WakeLock released by handleMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@ce8e03)
11-29 09:07:59.281 1923 1943 W Looper : Slow dispatch took 452ms android.ui h=android.view.Choreographer$FrameHandler c=android.view.Choreographer$FrameDisplayEventReceiver@9a713dc m=0
11-29 09:07:59.281 1923 1943 W Looper : Slow delivery took 538ms android.ui h=android.view.ViewRootImpl$ViewRootHandler c=null m=6
11-29 09:07:59.355 1923 1943 W Looper : Drained
11-29 09:08:00.229 1923 2276 I GnssLocationProvider: WakeLock acquired by sendMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@cdd90f1)
11-29 09:08:00.229 1923 1941 I GnssLocationProvider: WakeLock released by handleMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@cdd90f1)
11-29 09:08:00.607 1825 1831 D gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
11-29 09:08:00.608 1825 1831 D : HostConnection::get() New Host Connection established 0xf0ebc240, tid 1831
11-29 09:08:00.608 1825 1831 D gralloc_ranchu: gralloc_unregister_buffer: exiting HostConnection (is buffer-handling thread)
11-29 09:08:00.643 1825 1831 D : HostConnection::get() New Host Connection established 0xf0ebc240, tid 1831
11-29 09:08:01.230 1923 2276 I GnssLocationProvider: WakeLock acquired by sendMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@7e654d6)
11-29 09:08:01.230 1923 1941 I GnssLocationProvider: WakeLock released by handleMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@7e654d6)
11-29 09:08:01.537 1825 1829 D hwcomposer: hw_composer sent 343 syncs in 60s
11-29 09:08:01.563 1580 1664 W audio_hw_generic: Not supplying enough data to HAL, expected position 1844103 , only wrote 1692000
11-29 09:08:02.230 1923 2276 I GnssLocationProvider: WakeLock acquired by sendMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@e6f8357)
11-29 09:08:02.230 1923 1941 I GnssLocationProvider: WakeLock released by handleMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@e6f8357)
11-29 09:08:02.293 1774 1812 E storaged: getDiskStats failed with result NOT_SUPPORTED and size 0
11-29 09:08:02.691 1923 1941 I UsageStatsService: User[0] Flushing usage stats to disk
I have a feeling that this is caused by the incompentency between react-native 0.60 and newly utilised react-native-fs, because when I am trying to configure the react-native-fs in rn 0.60 environment, it throws a lot of error such as fs error, and react-native-fs documentation is conflect about whether use auto or manul "react-native link" cmd if rn version is higher than 0.60. Use "react-native link react-native-fs" is obsolutely fine in rn 0.59, but it does not work in 0.60, for some of the configurations does not show in the build.gradle and MainApplication.java.
Many thanks.
@gitathrun from your error log it looks like the problem is with accessing a microphone (maybe a permissions error)? If you fix that do you get any other errors?
It also sounds like you weren't able to get react-native-fs set up where you using RN 0.60 or a version > 0.61. The readme for react-native-fs seems to suggest you need to use RN 0.61 or higher.
@tafsiri Here is the weired part. I have never try to setup the microphone permission or usage in this simple demo, the code is identical with version 0.59. But the rn 60 asks for this permission? This is the part I am not certain about.
The second odd thing is, according to react-native-fs doc,
For RN >= 0.57 and/or Gradle >= 3 you MUST install react-native-fs at version >= @2.13.2!
But with this version 2.13.x, the android build failed as this indicates, update solved this problem in build, bundle process, but encountered the flash-crash problem.
May be it has to be react-native 0.61, I am not sure, but my current project are based on 0.60.
I will test this against 0.61, to see if it is the solution.
Automatically closing due to lack of recent activity. Please update the issue when new information becomes available, and we will reopen the issue. Thanks!
@tafsiri @gitathrun I have run into this same issue trying to use this library's custom fetch implementation in an Android emulator and was wondering if either of you have made any further progress on this? It seems like the issue was closed prematurely without resolution.
@dkoo are you getting the same error (a microphone exception?) Feel free to make a new issue with your setup and I can take a look. The main issue is that I haven't been able to reproduce this.
@tafsiri In my case it's not due to a microphone exception (I'm not even using the microphone, I'm just trying to capture a still photo from React Native Camera or select one from the photo library). It seems related to the use of fetch to try to turn either a local file or base64 string into a binary stream for consumption by decodeJpeg. Code sample:
const convertImageToTensor = async ( image ) => {
const binary = await fetch( image.uri, {}, { isBinary: true } ); // This is the line that is causing the `Network request failed` error in Android.
const raw = await binary.arrayBuffer();
const buffer = new Uint8Array( raw );
const tensor = await decodeJpeg( buffer );
classifyImage( tensor );
};
// Take a picture using camera component ref and pass to TensorFlow.
const capturePhoto = async () => {
if ( cameraRef.current ) {
const image = await cameraRef.current.takePictureAsync( {
base64: true,
doNotSave: true, // Do not save image file to device disk.
exif: false,
quality: 0.5
} );
if ( image.base64 ) {
image.uri = 'data:image/jpeg;base64,' + image.base64;
}
convertImageToTensor( image );
}
};
This works as expected on iOS, but the XHR request fails on Android. It also fails when trying to fetch a .jpg file from the device's disk, not just when fetching a base64 data URI. I thought it might have been related to this issue: https://github.com/facebook/react-native/issues/23986
but that didn't seem to fix the problem. Debugging the custom fetch function, I saw that the request kept erroring out with a status of 0 before the content type could be determined. I then tried manually setting a content-type header to image/jpeg, but that didn't work either. So I ended up sidestepping the issue by manually building the binary instead:
// Revised function avoiding the use of `fetch` or XHR to convert the image to binary.
const convertImageToTensor = async ( image ) => {
let binary,
raw,
buffer;
if ( image.base64 ) {
binary = atob( image.base64 );
raw = new ArrayBuffer( binary.length );
buffer = new Uint8Array( raw );
for ( let i = 0; i < binary.length; i ++ ) {
buffer[i] = binary.charCodeAt( i );
}
const tensor = await decodeJpeg( buffer );
classifyImage( tensor );
}
};
This seems to work on both iOS and Android. Still, it's more of a workaround than addressing the actual issue with the fetch method.
@dkoo thanks for the updated info. Could you also let me know what versions of tfjs and tfjs-react-native you are using? Also is this just in the simulator or also on device?
@tafsiri Sorry for the delayed response. Versions I'm using:
"@tensorflow/tfjs": "^1.5.1",
"@tensorflow/tfjs-react-native": "0.1.0-alpha.3",
And this was in the Android Emulator.
Thanks, any chance you could try this on a physical device?
Automatically closing due to lack of recent activity. Please update the issue when new information becomes available, and we will reopen the issue. Thanks!