使用 Google Cloud Storage 将音频文件从 Google Text-to-Speech 保存到 Firebase Storage? [英] Save an audiofile from Google Text-to-Speech to Firebase Storage using Google Cloud Storage?
问题描述
我们正在尝试使用 Google Cloud Function 从 Google Text-to-Speech 获取音频文件并将其保存到 Firebase Storage.Google 的文档Text-to-Speech 展示了如何获取音频文件并将其保存在本地:
We're trying to get an audiofile from Google Text-to-Speech and save it to Firebase Storage, using a Google Cloud Function. The documentation for Google Text-to-Speech show how to get an audiofile and save it locally:
// Performs the Text-to-Speech request
const [response] = await client.synthesizeSpeech(request);
// Write the binary audio content to a local file
const writeFile = util.promisify(fs.writeFile);
await writeFile('output.mp3', response.audioContent, 'binary');
console.log('Audio content written to file: output.mp3');
这会导致错误消息Error: EROFS: read-only file system
.Google Cloud Storage 不允许在本地写入文件.
This results in an error message Error: EROFS: read-only file system
. Google Cloud Storage doesn't allow writing files locally.
使用 Firebase 存储 bucket.upload()
有几个问题:
Using Firebase Storage bucket.upload()
has a few problems:
const destinationPath = 'Audio/Spanish' + filename.ogg;
// Performs the Text-to-Speech request
const [response] = await client.synthesizeSpeech(request);
// response.audioContent is the downloaded file
await bucket.upload(response.audioContent, {
destination: destinationPath
));
错误信息是TypeError: Path must be a string
.bucket.upload()
的第一个参数是 您希望上传到存储桶的文件的完全限定路径.
并且应该是一个字符串,所以 response.audioContent
不起作用.
The error message is TypeError: Path must be a string
. The first parameter of bucket.upload()
is The fully qualified path to the file you wish to upload to your bucket.
and is expected to be a string so response.audioContent
doesn't work.
文档 bucket.upload()
建议 destination:destinationPath
是我们应该将路径放置到 Firebase 存储位置的位置.这是正确的吗?
The documentation for bucket.upload()
suggests that destination: destinationPath
is where we should put the path to the Firebase Storage location. Is this correct?
我们如何从 Google Text-to-Speech (response.audioContent
) 中获取音频文件并将其保存为 bucket.upload()
可以访问的字符串?或者我们应该使用其他东西来代替 bucket.upload()
?
How do we take the audiofile from Google Text-to-Speech (response.audioContent
) and save it as a string that bucket.upload()
can access? Or should we use something else instead of bucket.upload()
?
这是我们完整的云功能:
Here's our full cloud function:
exports.Google_T2S = functions.firestore.document('Users/{userID}/Spanish/T2S_Request').onUpdate((change, context) => {
if (change.after.data().word != undefined) {
// Performs the Text-to-Speech request
async function test() {
try {
const word = change.after.data().word; // the text
const longLanguage = 'Spanish';
const audioFormat = '.mp3';
// copied from https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries#client-libraries-usage-nodejs
const fs = require('fs');
const util = require('util');
const textToSpeech = require('@google-cloud/text-to-speech'); // Imports the Google Cloud client library
const client = new textToSpeech.TextToSpeechClient(); // Creates a client
let myWordFile = word.replace(/ /g,"_"); // replace spaces with underscores in the file name
myWordFile = myWordFile.toLowerCase(); // convert the file name to lower case
myWordFile = myWordFile + audioFormat; // append .mp3 to the file name;
// copied from https://cloud.google.com/blog/products/gcp/use-google-cloud-client-libraries-to-store-files-save-entities-and-log-data
const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
const bucket = storage.bucket('myProject-cd99d.appspot.com');
const destinationPath = 'Audio/Spanish/' + myWordFile;
const request = { // Construct the request
input: {text: word},
// Select the language and SSML Voice Gender (optional)
voice: {languageCode: 'es-ES', ssmlGender: 'FEMALE'},
// Select the type of audio encoding
audioConfig: {audioEncoding: 'MP3'},
};
const [response] = await client.synthesizeSpeech(request);
// Write the binary audio content to a local file
const writeFile = util.promisify(fs.writeFile);
await writeFile('output.mp3', response.audioContent, 'binary');
console.log('Audio content written to file: output.mp3')
// response.audioContent is the downloaded file
await bucket.upload(response.audioContent, {
destination: destinationPath
});
}
catch (error) {
console.error(error);
}
}
test();
} // close if
return 0; // prevents an error message "Function returned undefined, expected Promise or value"
});
推荐答案
file.save()
就是答案.util.promisify
是不必要的,并且会导致关于 original
的错误消息.这是完成的云函数:
file.save()
was the answer. util.promisify
was unnecessary, and causes an error message about original
something. Here's the finished cloud function:
const functions = require('firebase-functions');
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
async function textToSpeechRequest()
{
try
{
const word = change.after.data().word; // the text
const longLanguage = 'Spanish';
const audioFormat = '.mp3';
// copied from https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries#client-libraries-usage-nodejs
const util = require('util');
const textToSpeech = require('@google-cloud/text-to-speech'); // Imports the Google Cloud client library
const client = new textToSpeech.TextToSpeechClient(); // Creates a client
let myWordFile = word.replace(/ /g,"_"); // replace spaces with underscores in the file name
myWordFile = myWordFile.toLowerCase(); // convert the file name to lower case
myWordFile = myWordFile + audioFormat; // append .mp3 to the file name;
// copied from https://cloud.google.com/blog/products/gcp/use-google-cloud-client-libraries-to-store-files-save-entities-and-log-data
const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
//const bucket = storage.bucket('myProject-cd99d.appspot.com');
var file = bucket.file('Audio/Spanish/' + myWordFile);
const request = { // Construct the request
input: {text: word},
// Select the language and SSML Voice Gender (optional)
voice: {languageCode: 'es-ES', ssmlGender: 'FEMALE'},
// Select the type of audio encoding
audioConfig: {audioEncoding: 'MP3'},
};
const options = { // construct the file to write
metadata: {
contentType: 'audio/mpeg',
metadata: {
source: 'Google Text-to-Speech'
}
}
};
// copied from https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries#client-libraries-usage-nodejs
const [response] = await client.synthesizeSpeech(request);
// Write the binary audio content to a local file
// response.audioContent is the downloaded file
return await file.save(response.audioContent, options)
.then(() => {
console.log("File written to Firebase Storage.")
return;
})
.catch((error) => {
console.error(error);
});
} // close try
catch (error) {
console.error(error);
} // close catch
} // close async function declaration
exports.Google_T2S = functions.firestore.document('Users/{userID}/Spanish/T2S_Request').onUpdate((change, context) => {
if (change.after.data().word !== undefined)
{
textToSpeechRequest();
} // close if
}); // close Google_T2S
我们收到一个错误TypeError: [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type function at Object.promisify
.此错误似乎不会影响云功能.
We're getting an error TypeError: [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type function at Object.promisify
. This error doesn't appear to effect the cloud function.
重申那些不起作用的东西,fs.createWriteStream
不起作用,因为 Google Cloud Functions 无法处理 节点文件系统 命令.相反,Google Cloud Functions 有自己的 方法Node 文件系统命令.bucket.upload() 将上传本地文件到存储桶,但本地文件的路径必须是字符串,而不是缓冲区或来自 API 的流.file.save() 记录为
To reiterate the stuff that didn't work, fs.createWriteStream
didn't work because Google Cloud Functions can't handle Node file system commands. Instead, Google Cloud Functions have their own methods that wrap the Node file system commands. bucket.upload() will upload a local file to a bucket, but the path to the local file has to be a string, not a buffer or a stream coming from an API. file.save() is documented as
将任意数据写入文件.
这是一个包装File#createWriteStream
的便捷方法.
This is a convenience method which wraps File#createWriteStream
.
这就是我想要的!如果我的数据有一件事,那是任意的.或者可能是天生相反.之后我们只需要理顺contentType
(audio/mpeg
,而不是mp3
)和文件路径.
That's what I want! If there's one thing about my data, it's arbitrary. Or maybe contrary by nature. After that we just had to straighten out the contentType
(audio/mpeg
, not mp3
) and the file path.
这篇关于使用 Google Cloud Storage 将音频文件从 Google Text-to-Speech 保存到 Firebase Storage?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!