I have a custom trained tensorflow.js graph model (link can be found in the getModel method) to recognize images of fly agarics. However, the prediction output (result from model.executeAsync()) never changes - this is evident in the console.log in the renderPredictions method.
Greatly appreciate any help.
webcamView.tsx
import { useEffect, useRef, useState } from "react";
import * as tf from '#tensorflow/tfjs-core';
import { loadGraphModel } from "#tensorflow/tfjs-converter";
import '#tensorflow/tfjs-backend-cpu';
export default function WebcamView() {
const videoWidth = 640;
const videoHeight = 500;
const videoRef = useRef<HTMLVideoElement>(null);
const [loading, setLoading] = useState<Boolean>(true);
let model: any = undefined;
const getModel = async () => {
model = await loadGraphModel('https://raw.githubusercontent.com/AlanChen4/FungEye/main/data/web_model_old/model.json');
return model;
};
const startVideo = async () => {
navigator.mediaDevices.getUserMedia({
video: {
facingMode: 'environment',
}
}).then(stream => {
if (videoRef.current !== null) {
const video = videoRef.current;
video.srcObject = stream;
video.onloadedmetadata = () => {
video.play();
video.addEventListener('loadeddata', processVideoInput);
}
}
})
};
const renderPredictions = (predictions: any) => {
const predictionBoxes = predictions[6].dataSync();
const predictionClasses = predictions[2].dataSync();
const predictionScores = predictions[4].dataSync();
// this always prints the same scores
console.log(predictionScores);
};
const processVideoInput = () => {
// classify the frame in the video stream and then repeat to process the next frame
if (videoRef.current !== null) {
classifyVideoInput(videoRef.current).then(() => {
window.requestAnimationFrame(processVideoInput);
})
}
}
const classifyVideoInput = async (videoImage: HTMLVideoElement) => {
// get next video frame
await tf.nextFrame();
// convert tensor to image
const tfImage = tf.browser.fromPixels(videoImage);
// convert image to smaller image in order to match detection size
const smallerImage = tf.image.resizeBilinear(tfImage, [videoHeight, videoWidth]);
// convert smaller image to format usable by model
const resizedImage = tf.cast(smallerImage, 'int32');
let tf4d_ = tf.tensor4d(Array.from(resizedImage.dataSync()), [1, videoHeight, videoWidth, 3]);
const tf4d = tf.cast(tf4d_, 'int32');
// generate predictions from model
let predictions = await model.executeAsync(tf4d);
renderPredictions(predictions);
tfImage.dispose();
smallerImage.dispose();
resizedImage.dispose();
tf4d.dispose();
};
useEffect(() => {
const start = async () => {
await getModel();
await startVideo();
setLoading(false);
};
start();
}, []);
return (
<div className="p-8">
<div className="flex justify-center p-5">
<div id="videoView" style={{ cursor: 'pointer' }}>
{loading
? <p className="text-center text-semibold p-5">Loading Model...</p>
: <video ref={videoRef} playsInline autoPlay muted width={videoWidth} height={videoHeight}></video>
}
</div>
</div>
</div>
);
};
I have checked to make sure that video processing only occurs after the video has loaded. I've checked numerous threads and posts but can not seem to find the cause of this issue. I am using tensorflow.js 3.1.0.
Related
I retrieve the available taxis' latitude and longitude coordinate pairs from the response.data.value of the LTA taxi availability API (https://datamall.lta.gov.sg/content/datamall/en/dynamic-data.html).
In CurCoord.js, I obtain the user's current coordinates.
In CountNearby.js, I implemented the logic to compare the available taxis' coordinates against the user's current coordinates to output an array of nearby coordinates.
However, there is no output rendered on the screen.
I've published my code on https://github.com/OngJinHui/proj2_taxi.git.
On a side note, please click on the button "request temporary access to the demo server" on the https://cors-anywhere.herokuapp.com/corsdemo page to activate the cors session to start retrieving the data from the API call.
I tried to loop through the available taxis' coordinates to find those that were close by to the user's current coordinates but I'm not getting any output even when I've adjusted the difference to 0.01.
CountNearby.js
import CurCoord from './CurCoord';
import { useState } from "react";
const CountNearby = (props) => {
const [closeToUserPoints, setCloseToUserPoints] = useState({});
const handlerCurrentCoord = (latitude, longitude) => {
props.latLon.forEach(individual_point => {
if ((Math.abs(individual_point.Latitude - latitude) < 0.01) &&
(Math.abs(individual_point.Longitude - longitude) < 0.01)) {
const placeholderSetOfPoints = {...closeToUserPoints}
placeholderSetOfPoints.append({nearbyLatitude: individual_point.Latitude,
nearbyLongitude: individual_point.Longitude});
setCloseToUserPoints(placeholderSetOfPoints)
}
});
};
return (
<div>
<CurCoord onCurrentCoord = {handlerCurrentCoord} />
<p>{closeToUserPoints[0]}</p>
</div>
);
};
export default CountNearby;
CurCoord.js
import React, { useState, useEffect } from 'react';
const CurCoord = (props) => {
const [lat, setLat] = useState(null);
const [lng, setLng] = useState(null);
const [status, setStatus] = useState(null);
const getLocation = () => {
if (!navigator.geolocation) {
setStatus('Geolocation is not supported by your browser');
} else {
setStatus('Locating...');
navigator.geolocation.getCurrentPosition((position) => {
setStatus(null);
setLat(position.coords.latitude);
setLng(position.coords.longitude);
}, () => {
setStatus('Unable to retrieve your location');
});
props.onCurrentCoord(lat, lng);
}
}
useEffect(() => {
getLocation();
}, [lat, lng])
return (
<div className="App">
<button onClick={getLocation}>Get Location</button>
<h1>Coordinates</h1>
<p>{status}</p>
{lat && <p>Latitude: {lat}</p>}
{lng && <p>Longitude: {lng}</p>}
</div>
);
}
export default CurCoord;
Thanks!
I am making a mern ecommerce website i just want to see how useEffect works so i console.log in some part of useEffect and loadFilteredResults i saw that --->
initial
entry
skip
entry1
screen shot
but i think it shoud be-->
initial
entry
entry1
skip
why console give this?? i am a begginer, i am a self learner , so please if you need any extra info please comment.
code snippet-->
const loadFilteredResults = (newFilters) => {
console.log("entry")
getFilteredProducts(skip, limit, newFilters).then((data) => {
console.log("entry1")
if (data.error) {
setError(data.error);
} else {
//console.log(data);
setFilteredResults(data.data);
//console.log("size-->");
//console.log(data.size);
setSize(data.size);
setSkip(0);
}
});
};
....
....
useEffect(() => {
init();
console.log("initial");
loadFilteredResults(skip, limit, myFilters.filters);
console.log("skip");
}, []);
//full code of shop.js
import React, { useEffect, useState } from "react";
import Layout from "./Layout";
import Card from "./Card";
import { getCategories, getFilteredProducts } from "./apiCore";
import Checkbox from "./Checkbox";
import RadioBox from "./RadioBox";
import { prices } from "./fixedPrices";
const Shop = () => {
const [myFilters, setMyFilters] = useState({
filters: { category: [], price: [] }
});
const [categories, setCategories] = useState([]);
const [error, setError] = useState(false);
const [limit, setLimit] = useState(3);//prpduct lesss so use 3 but sir used 6
const [skip, setSkip] = useState(0);
const [size, setSize] = useState(0);
const [filteredResults, setFilteredResults] = useState([]);
const init = () => {
getCategories().then((data) => {
if (data.error) {
//console.log("error");
setError(data.error);
} else {
//console.log("set");
//console.log(data);
setCategories(data);
//console.log(data);
}
});
};
const loadFilteredResults = (newFilters) => {
//console.log(newFilters);
console.log("entry")
getFilteredProducts(skip, limit, newFilters).then((data) => {
console.log("entry1")
if (data.error) {
setError(data.error);
} else {
//console.log(data);
setFilteredResults(data.data);
//console.log("size-->");
//console.log(data.size);
setSize(data.size);
setSkip(0);
}
});
};
const loadMore = () => {
console.log("skip"+skip);
console.log("limit"+limit);
let toSkip = skip + limit;
console.log("toSkip"+toSkip);
getFilteredProducts(toSkip, limit, myFilters.filters).then((data) => {
//console.log("filter");
//console.log( myFilters.filters)
if (data.error) {
setError(data.error);
} else {
//console.log(filteredResults);
//console.log(data.data);
setFilteredResults([...filteredResults, ...data.data]);
//console.log("after");
//console.log(...filteredResults);
//console.log(filteredResults);
//console.log(filteredResults);
//console.log([...filteredResults])
//console.log([...filteredResults, ...data.data])
setSize(data.size);
setSkip(toSkip);
}
});
};
const loadMoreButton = () => {
return (
size > 0 &&
size >= limit && (
<button onClick={loadMore} className="btn btn-warning mb-5">
load more
</button>
)
);
};
useEffect(() => {
init();
//console.log(skip);
console.log("initial");
loadFilteredResults(skip, limit, myFilters.filters);
console.log("skip");
}, []);
const handleFilters = (filters, filterBy) => {
//console.log("SHOP", filters, filterBy);
const newFilters = { ...myFilters };
//console.log(newFilters);
newFilters.filters[filterBy] = filters;
//console.log(typeof(filters));
if (filterBy === "price") {
let priceValues = handlePrice(filters);
newFilters.filters[filterBy] = priceValues;
//console.log(priceValues);
}
//console.log(myFilters.filters);
loadFilteredResults(myFilters.filters);
setMyFilters(newFilters);
};
const handlePrice = (value) => {
const data = prices;
let array = [];
//console.log(value);
for (let key in data) {
if (data[key]._id === parseInt(value)) {
array = data[key].array;
}
}
return array;
};
// const x = (filters)=>{
// console.log("filters:"+filters);
// handleFilters(filters, "category")
// }
return (
<Layout
title="Shop Page"
description="search and buy books of your choice"
className="container-fluid"
>
<div className="row">
<div className="col-4">
<h4>Filter by categories</h4>
<ul>
{/* below will be show in list show we wrap it in unorder list */}
<Checkbox
categories={categories}
handleFilters={(filters) =>
handleFilters(filters, "category")
}
/>
</ul>
<h4>Filter by price range</h4>
<div>
<RadioBox
prices={prices}
handleFilters={(filters) => handleFilters(filters, "price")}
/>
</div>
</div>
<div className="col-8">
<h2 className="mb-4">Products</h2>
<div className="row">
{filteredResults.map((product, i) => (
<Card key={i} product={product} />
))}
</div>
<hr />
{loadMoreButton()}
</div>
</div>
</Layout>
);
};
export default Shop;
getFilteredProducts must be a Promise. Please read Using promises
Callbacks added with then() will never be invoked before the
completion of the current run of the JavaScript event loop.
In React (Next.js) with hooks using typescript, I want to create a reference to Audio. The error I'm getting is:-
Property 'duration' does not exist on type 'false | HTMLAudioElement'.
Property 'duration' does not exist on type 'false'.ts(2339)
const audioRef = useRef(typeof Audio !== 'undefined' && new Audio(mp3Src));
const { duration } = audioRef.current.duration;
I've also tried like this
const audioRef = useRef(new Audio(mp3Src));
const { duration } = audioRef.current;
which then throws an error in the browser
Server Error
ReferenceError: Audio is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Complete code
import type { NextPage } from 'next';
import React, { useRef, useState } from 'react';
import Image from 'next/image';
interface Props {
imgSrc: string;
mp3Src: string;
}
const AudioPlayer: NextPage<Props> = ({ imgSrc, mp3Src }) => {
// const audioRef = useRef(new Audio(mp3Src));
const audioRef = useRef(typeof Audio !== 'undefined' && new Audio(mp3Src));
// const duration = audioRef.current.duration;
const { duration } = audioRef.current;
const intervalRef = useRef<any>();
const [trackProgress, setTrackProgress] = useState<number>(0);
const [isPlaying, setIsPlaying] = useState<boolean>(false);
const play = (): void => {
audioRef.current.play();
startTimer();
setIsPlaying(true);
};
const pause = (): void => {
audioRef.current.pause();
setIsPlaying(false);
};
const startTimer = (): void => {
clearInterval(intervalRef.current);
intervalRef.current = setInterval(() => {
setTrackProgress(audioRef.current.currentTime);
}, 100);
};
const onScrub = (value: number): void => {
// Clear any timers already running
clearInterval(intervalRef.current);
audioRef.current.currentTime = value;
setTrackProgress(audioRef.current.currentTime);
};
const onScrubEnd = (): void => {
if (!isPlaying) {
setIsPlaying(true);
}
startTimer();
};
const mute = (): void => {
audioRef.current.volume = 0;
};
return (
<div className='AudioPlayer'>
<Image alt='menu' src={imgSrc} width='30' height='20' />
<div onClick={play}>Play</div>
<div onClick={pause}>Pause</div>
<div>{trackProgress}</div>
<div>{isPlaying}</div>
<input
type='range'
value={trackProgress}
step='1'
min='0'
max={duration ? duration : `${duration}`}
className='progress'
onChange={(e): void => onScrub(+e.target.value)}
onMouseUp={onScrubEnd}
onKeyUp={onScrubEnd}
/>
<div onClick={mute}>Mute</div>
</div>
);
};
export default AudioPlayer;
NextJS uses Node to render anything in the server that allows you to build static and server side rendered apps. Therefore, any browser's APIs such as window or in your case Audio, do not exist in Node.
When Next tries to run the following code on node, and since Audio does not exist. It will evaluate to false since typeof Audio is undefined.
const audioRef = useRef(typeof Audio !== 'undefined' && new Audio(mp3Src));
To ensure the code is run only on browsers (not Node), you can use the useEffect hook.
e.g.
const AudioPlayer: NextPage<Props> = ({ imgSrc, mp3Src }) => {
// const audioRef = useRef(new Audio(mp3Src));
const [audioElem, setAudioElem] = useState<HTMLAudioElement>();
useEffect(() => {
if (typeof Audio !== 'undefined' && mp3Src) {
const audio = new Audio(mp3Src);
setAudioElem(audio);
}
}, [mp3Src])
// const duration = audioRef.current.duration;
const { duration } = audioElem || {};
...
Some helpful links;
https://dev.to/vvo/how-to-solve-window-is-not-defined-errors-in-react-and-next-js-5f97
https://frontend-digest.com/why-is-window-not-defined-in-nextjs-44daf7b4604e
My goal is to use the button on the page to open a websocket connection, subscribe to the ticker feed, then update each list item's price based on the ID of the list item. Currently I have a list that maps through the initial API call's response and saves each object's ID to an array, which in turn is used to build a <li> for each ID. This creates 96 list items. I have also gotten the price to update live via a <p> element in each <li>.
I am having trouble targeting the price for just the matching row ID to the incoming data object's ID so that only that matching row is re-rendered when it gets a match. Below is my code:
ProductRow.js
import React from 'react';
export default function ProductRow(props) {
return <li key={props.id}><p>{ props.id }</p><p>{props.price}</p></li>;
}
WatchList.js
import React, { useState, useEffect, useRef } from "react";
import { Button } from 'react-bootstrap';
import ProductRow from "./ProductRow";
export default function WatchList() {
const [currencies, setcurrencies] = useState([]);
const product_ids = currencies.map((cur) => cur.id);
const [price, setprice] = useState("0.00");
const [isToggle, setToggle] = useState();
const ws = useRef(null);
let first = useRef(false);
const url = "https://api.pro.coinbase.com";
useEffect(() => {
ws.current = new WebSocket("wss://ws-feed.pro.coinbase.com");
let pairs = [];
const apiCall = async () => {
await fetch(url + "/products")
.then((res) => res.json())
.then((data) => (pairs = data));
let filtered = pairs.filter((pair) => {
if (pair.quote_currency === "USD") {
return pair;
}
});
filtered = filtered.sort((a, b) => {
if (a.base_currency < b.base_currency) {
return -1;
}
if (a.base_currency > b.base_currency) {
return 1;
}
return 0;
});
setcurrencies(filtered);
first.current = true;
};
apiCall();
}, []);
useEffect(() => {
ws.current.onmessage = (e) => {
if (!first.current) {
return;
}
let data = JSON.parse(e.data);
if (data.type !== "ticker") {
return;
}
setprice(data.price);
console.log(data.product_id, price);
};
}, [price]);
const handleToggleClick = (e) => {
if (!isToggle) {
let msg = {
type: "subscribe",
product_ids: product_ids,
channels: ["ticker"]
};
let jsonMsg = JSON.stringify(msg);
ws.current.send(jsonMsg);
setToggle(true);
console.log('Toggled On');
}
else {
let unsubMsg = {
type: "unsubscribe",
product_ids: product_ids,
channels: ["ticker"]
};
let unsub = JSON.stringify(unsubMsg);
ws.current.send(unsub);
setToggle(false);
console.log('Toggled Off');
}
};
return (
<div className="container">
<Button onClick={handleToggleClick}><p className="mb-0">Toggle</p></Button>
<ul>
{currencies.map((cur) => {
return <ProductRow id={cur.id} price={price}></ProductRow>
})}
</ul>
</div>
);
}
App.js
import React from "react";
import WatchList from "./components/Watchlist";
import "./scss/App.scss";
export default class App extends React.Component {
render() {
return (
<WatchList></WatchList>
)
}
}
Initialize the price state to be an empty object i.e. {}. We'll refer the price values by the the product_id on getting the response from websocket
// Initialize to empty object
const [price, setprice] = useState({});
...
// Refer and update/add the price by the product_id
useEffect(() => {
ws.current.onmessage = (e) => {
if (!first.current) {
return;
}
let data = JSON.parse(e.data);
if (data.type !== "ticker") {
return;
}
// setprice(data.price)
setprice(prev => ({ ...prev, [data.product_id]: data.price}));
console.log(data.product_id, price);
};
}, [price]);
Render your ProductRows as
<ul>
{currencies.map((cur) => {
return <ProductRow key={cur.id} id={cur.id} price={price[cur.id]}></ProductRow>
})}
</ul>
You don't have to manage anykind of sorting or searching for the relevant prices for products.
import React, { useState, useEffect } from 'react';
importing my hooks
function useFetch(url, defaultResponse) {
const [data, setData] = useState(defaultResponse);
async function getDataFromAPI(url) {
try {
const res = await fetch(url);
const data = await res.json();
setData({
isLoading: false,
data
})
} catch (e) {
console.log(e);
}
}
useEffect(() => {
getDataFromAPI(url);
}, [url])
return data;
}
Created a custom hook
export default function YouTubeData() {
const channelID = "UCXgGY0wkgOzynnHvSEVmE3A";
const APIKEY = "my-working-key";
const results = 4
const apiEndpoint = `https://www.googleapis.com/youtube/v3/search?key=${APIKEY}&channelId=${channelID}&part=snippet,id&order=date&&maxResults=${results}`
const userFetchResponse = useFetch(apiEndpoint, { isLoading: true, data: null });
if (!userFetchResponse.data || userFetchResponse.isLoading) {
return 'Loading...'
}
When I console log userFetchResponse.data.items I get an object array with properties
const {videoId} = (userFetchResponse.data.items.map(obj => "http://www.youtube.com/embed/" + obj.id.videoId));
return (
<div>
{
videoId.map((link, i) => {
var frame =
<div key={i} className='youtube'>
<iframe
title={i}
width="560"
height="315"
src={link}
frameBorder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen>
</iframe>
</div>
return frame
})
}
{this.frame}
</div>
)
}
I am trying to create a variable videoID to hold an array of the 4 URLs I will need for the jsx src but I keep getting an error of undefined can someone help?
const {videoId} = (userFetchResponse.data.items.map(obj => "http://www.youtube.com/embed/" + obj.id.videoId));
The right hand side is an array using map, the left hand side has to be an array as well.
const videoId = arr[0]
// or
const [videoId] = arr
But not {videoId, because that'll assume you have an object on the right hand side.
When you do
const {someVar} = something
Is the same as
const someVar = something.someVar
In your case, you only want to store an array into a variable, so you just need
const videoIds = userFetchResponse.data.items.map(obj => "http://www.youtube.com/embed/" + obj.id.videoId);