I have been looking to get back working on a JS Everest Flight Sim. Originally I had tried to create my own elevation mesh and tiles using DEM elevation data and mapping it to vertices Z axis.
I decided using Mapbox RGB tiles for elevation data would be a better approach. Unfortunately I can't seem to get it to work. The Omaha Nebraska doc example works but now the Mt. Everest tile.
I've brought the issue up here as well: https://github.com/mapbox/sphericalmercator/issues/43
Perhaps someone from Mapbox can offer me some insights :)
import fs from "fs";
import dotenv from "dotenv";
import fetch from "node-fetch";
import SphericalMercator from "#mapbox/sphericalmercator";
dotenv.config();
const queryMapbox = async () => {
const merc = new SphericalMercator({
size: 256,
});
const xyFromLatLong = (lat, long, merc) => {
return merc.forward([long, lat]);
};
const zoom = 14;
const long = 86.922623;
const lat = 27.986065;
const xyPos = xyFromLatLong(lat, long, merc);
console.log({ xyPos });
try {
// Example from Docs - Omaha, Nebraska
// const response = await fetch(
// `https://api.mapbox.com/v4/mapbox.terrain-rgb/14/12558/6127.pngraw?access_token=${process.env.ACCESS_TOKEN}`
// );
// const filename = "omaha-rgb.png"
const response = await fetch(
`https://api.mapbox.com/v4/mapbox.terrain-rgb/${zoom}/${xyPos[0].toFixed(0)}/${xyPos[1].toFixed(0)}.pngraw?access_token=${process.env.ACCESS_TOKEN}`
);
const filename = "everest-rgb.png"
await new Promise((resolve, reject) => {
const fileStream = fs.createWriteStream(`./data/${filename}`);
response.body.pipe(fileStream);
response.body.on("error", (err) => {
reject(err);
});
fileStream.on("finish", function () {
resolve();
});
});
console.log({ response });
// console.log({ res });
} catch (err) {
console.error(err);
}
};
queryMapbox(); // Test
I think you are using the wrong library to convert lon, lat to tile x, y. The documentation mentions some libraries, including this one:
tilebelt: a set of JavaScript utilities for requesting and working with tiles.
Example:
const tilebelt = require("#mapbox/tilebelt");
console.log(tilebelt.pointToTile(86.922623, 27.986065, 14));
// Output:
// [ 12147, 6864, 14 ]
With those x and y the URL will be something like this:
https://api.mapbox.com/v4/mapbox.terrain-rgb/14/12147/6864.pngraw?access_token=YOUR_MAPBOX_ACCESS_TOKEN
Related
I'm just getting started with a simple project in node.js.
I'm trying to use Expo for the final app but get lots of dependency conflicts in the modules so was thinking of just calling the REST API via fetch. I have a test bed that works fine using the google-supplied modules, but I always get RecognitionAduio is not supplied as an error message via REST. As you can see in the attached code, the input file, coding etc are all identical.
any views?
async function getAudioTranscription() {
const fetch = require("node-fetch");
try {
var filename = 'C:/Users/SteveRist/Downloads/brooklyn.flac';
var encoding = 'FLAC';
var sampleRateHertz = 16000;
var languageCode = 'en-US';
const fs = require('fs');
const speech = require('#google-cloud/speech');
const client = new speech.SpeechClient();
console.log ('Setting REST config');
const config = {
encoding: encoding,
sampleRateHertz: sampleRateHertz,
languageCode: languageCode,
};
console.log ('opening ', filename);
const audio = {
content: fs.readFileSync(filename).toString('base64'),
};
const request = {
config: config,
audio: audio,
};
// Detects speech in the audio file. This creates a recognition job that you
// can wait for now, or get its result later.
const [operation] = await client.longRunningRecognize(request);
// Get a Promise representation of the final result of the job
const [response] = await operation.promise();
const transcription = response.results
.map(result => result.alternatives[0].transcript)
.join('\n');
console.log(`Transcription: ${transcription}`);
const transcriptResponse = await fetch(
'https://speech.googleapis.com/v1/speech:recognize?key=xxx8', {
method: 'POST',
request: request
}
);
const data = await transcriptResponse.json();
console.log ('transcriptResponse Google returned' , data);
const userMessage = data.results && data.results[0].alternatives[0].transcript || "";
console.log (userMessage);
} catch (error) {
console.log("There was an error", error);
}
}
getAudioTranscription();
I've build an javascript function with face-api.js for my react component which will return/console me the width and height of face detector box. I tried console.log in few places it seems working fine till the models(face-recognition-model).
But when I write async function for face detector to detect face and console. It gives me error-
Unhandled rejection(Reference Error): Cannot access 'handledImage' before initialization
Here is screen shot also.
I can't figure out, how to fix it?
There is my code faceDetector.js
import * as faceapi from "face-api.js";
//passing image from my react compoenent
const faceDetector = (image) => {
const imageRef = image;
const loadModels = async () => {
// models are present in public and they are getting loaded
const MODEL_URL = process.env.PUBLIC_URL + "/models";
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),
faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),
faceapi.nets.faceExpressionNet.loadFromUri(MODEL_URL)
])
// this is rising the issue. I want to call this function after my models loaded so it can detect face
.then(handleImage)
.catch((e) => console.error(e));
};
loadModels();
// this function should detect the face from imageRef and should console the size of detector
const handleImage = async () => {
const detections = await faceapi
.detectSingleFace(imageRef, new faceapi.TinyFaceDetectorOptions())
console.log(`Width ${detections.box._width} and Height ${detections.box._height}`);
}
}
export {faceDetector}
You need to change the order of function declaration. You can not call const variables before they were declared.
//passing image from my react component
const faceDetector = (image) => {
const imageRef = image;
// this function should detect the face from imageRef and should console the size of detector
const handleImage = async () => {
const detections = await faceapi
.detectSingleFace(imageRef, new faceapi.TinyFaceDetectorOptions())
console.log(`Width ${detections.box._width} and Height ${detections.box._height}`);
}
const loadModels = async () => {
// models are present in public and they are getting loaded
const MODEL_URL = process.env.PUBLIC_URL + "/models";
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),
faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),
faceapi.nets.faceExpressionNet.loadFromUri(MODEL_URL)
])
// this is rising the issue. I want to call this function after my models loaded so it can detect face
.then(handleImage)
.catch((e) => console.error(e));
};
loadModels();
}
I am using the Google TextToSpeech API in Node.js to generate speech from text. I was able to get an output file with the same name as the text that is generated for the speech. However, I need to tweak this a bit. I wish I could generate multiple files at the same time. The point is that I have, for example, 5 words (or sentences) to generate, e.g. cat, dog, house, sky, sun. I would like to generate them each to a separate file: cat.wav, dog.wav, etc.
I also want the application to be able to read these words from the * .txt file (each word/sentence on a separate line of the * .txt file).
Is there such a possibility? Below I am pasting the * .js file code and the * .json file code that I am using.
*.js
const textToSpeech = require('#google-cloud/text-to-speech');
const fs = require('fs');
const util = require('util');
const projectId = 'forward-dream-295509'
const keyFilename = 'myauth.json'
const client = new textToSpeech.TextToSpeechClient({ projectId, keyFilename });
const YourSetting = fs.readFileSync('setting.json');
async function Text2Speech(YourSetting) {
const [response] = await client.synthesizeSpeech(JSON.parse(YourSetting));
const writeFile = util.promisify(fs.writeFile);
await writeFile(JSON.parse(YourSetting).input.text + '.wav', response.audioContent, 'binary');
console.log(`Audio content written to file: ${JSON.parse(YourSetting).input.text}`);
}
Text2Speech(YourSetting);
*.json
{
"audioConfig": {
"audioEncoding": "LINEAR16",
"pitch": -2,
"speakingRate": 1
},
"input": {
"text": "Text to Speech"
},
"voice": {
"languageCode": "en-US",
"name": "en-US-Wavenet-D"
}
}
I'm not very good at programming. I found a tutorial on google on how to do this and slightly modified it so that the name of the saved file was the same as the generated text.
I would be very grateful for your help.
Arek
Here ya go - I haven't tested it, but this should show how to read a text file, split into each line, then run tts over it with a set concurrency. It uses the p-any and filenamify npm packages which you'll need to add to your project. Note that google may have API throttling or rate limits that I didn't take into account here - may consider using p-throttle library if that's a concern.
// https://www.npmjs.com/package/p-map
const pMap = require('p-map');
// https://github.com/sindresorhus/filenamify
const filenamify = require('filenamify');
const textToSpeech = require('#google-cloud/text-to-speech');
const fs = require('fs');
const path = require('path');
const projectId = 'forward-dream-295509'
const keyFilename = 'myauth.json'
const client = new textToSpeech.TextToSpeechClient({ projectId, keyFilename });
const rawSettings = fs.readFileSync('setting.json', { encoding: 'utf8'});
// base data for all requests (voice, etc)
const yourSetting = JSON.parse(rawSettings);
// where wav files will be put
const outputDirectory = '.';
async function Text2Speech(text, outputPath) {
// include the settings in settings.json, but change text input
const request = {
...yourSetting,
input: { text }
};
const [response] = await client.synthesizeSpeech(request);
await fs.promises.writeFile(outputPath, response.audioContent, 'binary');
console.log(`Audio content written to file: ${text} = ${outputPath}`);
// not really necessary, but you could return something if you wanted to
return response;
}
// process a line of text - write to file and report result (success/error)
async function processLine(text, index) {
// create output path based on text input (use library to ensure it's filename safe)
const outputPath = path.join(outputDirectory, filenamify(text) + '.wav');
const result = {
text,
lineNumber: index,
path: outputPath,
isSuccess: null,
error: null
};
try {
const response = await Text2Speech(text, outputPath);
result.isSuccess = true;
} catch (error) {
console.warn(`Failed: ${text}`, error);
result.isSuccess = false;
result.error = error;
}
return result;
}
async function processInputFile(filepath, concurrency = 3) {
const rawText = fs.readFileSync(filepath, { encoding: 'utf8'});
const lines = rawText
// split into one item per line
.split(/[\r\n]+/)
// remove surrounding whitespace
.map(s => s.trim())
// remove empty lines
.filter(Boolean);
const results = await pMap(lines, processLine, { concurrency });
console.log('Done!');
console.table(results);
}
// create sample text file
const sampleText = `Hello World
cat
dog
another line of text`;
fs.writeFileSync('./my-text-lines.txt', sampleText);
// process each line in the text file, 3 at a time
processInputFile('./my-text-lines.txt', 3);
I am trying to swap ETH for DAI tokens using the UniSwap SDK and javascript, but am getting the following error on running the script.
(node:10096) UnhandledPromiseRejectionWarning: Error: resolver or addr is not configured for ENS name (argument="name", value="", code=INVALID_ARGUMENT, version=contracts/5.0.5)
I have narrowed the error down to the uniswap.swapExactETHForTokens function but I still don't know how to fix it.
Full code: (Private keys are hidden from the code for obvious reasons)
const { ChainId, Fetcher, WETH, Route, Trade, TokenAmount, TradeType, Percent } = require('#uniswap/sdk');
const ethers = require('ethers');
const chainId = ChainId.MAINNET;
const tokenAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
const init = async () => {
const dai = await Fetcher.fetchTokenData(chainId, tokenAddress);
const weth = WETH[chainId];
const pair = await Fetcher.fetchPairData(dai, weth);
const route = new Route([pair], weth);
const trade = new Trade(route, new TokenAmount(weth, '1000000000000'), TradeType.EXACT_INPUT);
const slippageTolerance = new Percent('50', '10000');
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw;
const path = [weth.address, dai.address];
const to = '';
const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
const value = trade.inputAmount.raw;
const provider = ethers.getDefaultProvider('mainnet', {
infura: 'https://mainnet.infura.io/v3/ba14d1b3cfe5405088ee3c65ebd1d4'
});
const signer = new ethers.Wallet(PRIVATE_KEY);
const account = signer.connect(provider);
const uniswap = new ethers.Contract(
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
['function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)'],
account
);
const tx = await uniswap.swapExactETHForTokens(
amountOutMin,
path,
to,
deadline,
{ value, gasPrice: 20e9 }
);
console.log(`Transaction hash: ${tx.hash}`);
const receipt = await tx.wait();
console.log(`Transaction was mined in block ${receipt.blockNumber}`);
}
init();
I guess you can replace
const to = ''
by:
const to = process.env.ACCOUNT
providing your account / wallet address to which the targetTokens shall be sent.
In my case, I had directly copy-pasted the router address from the uniswap documentation. So my variable looked something like this:
const routerAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D ";
Since there was a space at the end of the string, the ethers.js library confused it for ENS name instead of an address. So I corrected it to this:
const routerAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D";
Guess it was a silly mistake, but just watch out for it, in case nothing works!
For those who are facing an INVALID ARGUMENT error, here's what worked for my (using React):
Import router02 :
import UniswapV2Router02 from '#uniswap/v2-periphery/build/UniswapV2Router02.json';
hex function:
const toHex = (currencyAmount) => `0x${currencyAmount.raw.toString(16)}`;
const amountOutMin = toHex(trade.minimumAmountOut(slippageTolerance));
const value = toHex(trade.inputAmount);
connect to blockchain
const provider = ethers.getDefaultProvider('mainnet', {
infura: 'JUST_INFURA_NUMBER eg. xxxxxxxxxx'
});
Get contract and methods:
const abi = UniswapV2Router02['abi'];
const uniswapRouter = new ethers.Contract(
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
abi,
account); //if this doesnt work, try using provider/signer instead of account
console.log("uniswap contract: ", uniswapRouter);
const tx = await uniswapRouter.swapExactETHForTokens(
amountOutMin,
path,
to,
deadline,
{value, gasPrice: 20e9, gasLimit: 250000}
);
Tutorial code: https://www.youtube.com/watch?v=0Im5iaYoz1Y
I have a cloud function that receives the uid of an image and associate it to the user who calls it after validating its dimensions and generate its thumbnail. It looks simple but I have to wait around 40 seconds to see the results, and sometimes it gets congested or something and I have to call the function again to see previous results.
Has anyone experience it before? How can I fix that?
exports.validateImageDimensions = functions
.region("us-central1")
.runWith({ memory: "2GB", timeoutSeconds: 120 })
.https.onCall(async (data, context) => {
As you can see the CPU used is high...
Thanks.
UPDATE
Code of the function:
exports.validateImageDimensions = functions
.region("us-central1")
.runWith({ memory: "2GB", timeoutSeconds: 120 })
.https.onCall(async (data, context) => {
// Libraries
const admin = require("firebase-admin");
const sizeOf = require("image-size");
const url = require("url");
const https = require("https");
const sharp = require("sharp");
const path = require("path");
const os = require("os");
const fs = require("fs");
// Lazy initialization of the Admin SDK
if (!is_validateImageDimensions_initialized) {
admin.initializeApp();
is_validateImageDimensions_initialized = true;
}
// Create Storage
const storage = admin.storage();
// Create Firestore
const firestore = admin.firestore();
// Get the image's owner
const owner = context.auth.token.uid;
// Get the image's info
const { id, description, location, tags } = data;
// Photos's bucket
const bucket = storage.bucket("bucket");
// File Path
const filePath = `photos/${id}`;
// Get the file
const file = getFile(filePath);
// Check if the file is a jpeg image
const metadata = await file.getMetadata();
const isJpgImage = metadata[0].contentType === "image/jpeg";
// Get the file's url
const fileUrl = await getUrl(file);
// Get the photo dimensions using the `image-size` library
https.get(url.parse(fileUrl), (response) => {
let chunks = [];
response
.on("data", (chunk) => {
chunks.push(chunk);
})
.on("end", async () => {
// Check if the image has valid dimensions
let dimensions = sizeOf(Buffer.concat(chunks));
// Create the associated Firestore's document to the valid images
if (isJpgImage && hasValidDimensions(dimensions)) {
// Create a thumbnail for the uploaded image
const thumbnailPath = await generateThumbnail(filePath);
// Get the thumbnail
const thumbnail = getFile(thumbnailPath);
// Get the thumbnail's url
const thumbnailUrl = await getUrl(thumbnail);
try {
await firestore
.collection("posts")
.doc(owner)
.collection("userPosts")
.add({
id,
uri: fileUrl,
thumbnailUri: thumbnailUrl, // Useful for progress images
description,
location,
tags,
date: admin.firestore.FieldValue.serverTimestamp(),
likes: [], // At the first time, when a post is created, zero users has liked it
comments: [], // Also, there aren't any comments
width: dimensions.width,
height: dimensions.height,
});
// TODO: Analytics posts counter
} catch (err) {
console.error(
`Error creating the document in 'posts/{owner}/userPosts/' where 'id === ${id}': ${err}`
);
}
} else {
// Remove the files that are not jpeg images, or whose dimensions are not valid
try {
await file.delete();
console.log(
`The image '${id}' has been deleted because it has invalid dimensions.
This may be an attempt to break the security of the app made by the user '${owner}'`
);
} catch (err) {
console.error(`Error deleting invalid file '${id}': ${err}`);
}
}
});
});
/* ---------------- AUXILIAR FUNCTIONS ---------------- */
function getFile(filePath) {
/* Get a file from the storage bucket */
return bucket.file(filePath);
}
async function getUrl(file) {
/* Get the public url of a file */
const signedUrls = await file.getSignedUrl({
action: "read",
expires: "01-01-2100",
});
// signedUrls[0] contains the file's public URL
return signedUrls[0];
}
function hasValidDimensions(dimensions) {
// Posts' valid dimensions
const validDimensions = [
{
width: 1080,
height: 1080,
},
{
width: 1080,
height: 1350,
},
{
width: 1080,
height: 750,
},
];
return (
validDimensions.find(
({ width, height }) =>
width === dimensions.width && height === dimensions.height
) !== undefined
);
}
async function generateThumbnail(filePath) {
/* Generate thumbnail for the progressive images */
// Download file from bucket
const fileName = filePath.split("/").pop();
const tempFilePath = path.join(os.tmpdir(), fileName);
const thumbnailPath = await bucket
.file(filePath)
.download({
destination: tempFilePath,
})
.then(() => {
// Generate a thumbnail using Sharp
const size = 50;
const newFileName = `${fileName}_${size}_thumb.jpg`;
const newFilePath = `thumbnails/${newFileName}`;
const newFileTemp = path.join(os.tmpdir(), newFileName);
sharp(tempFilePath)
.resize(size, null)
.toFile(newFileTemp, async (_err, info) => {
// Uploading the thumbnail.
await bucket.upload(newFileTemp, {
destination: newFilePath,
});
// Once the thumbnail has been uploaded delete the temporal file to free up disk space.
fs.unlinkSync(tempFilePath);
});
// Return the thumbnail's path
return newFilePath;
});
return thumbnailPath;
}
});
Pd: In the console I can read this record:
"Function execution took 103 ms, finished with status code: 200"
but I have to wait, as I said before, around 40 seconds to see the new doc on my firestore
You're not dealing with promises correctly. A callable function must return a promise that:
Resolves when all of the async work is complete
Resolves with the data to send back to the client
Right now, your function returns nothing, so it returns to the caller immediately, and the future of the async work that you kicked off is uncertain.
Note that https.get() is asynchronous and returns immediately, before its callback is invoked. You will need to find a way to instead return a promise that resovles when all of the callback's work is complete. (Consider that there are other HTTP client libraries that make it easier to get a promise instead of having to deal with callbacks.)