[英]Save an audiofile from Google Text-to-Speech to Firebase Storage using Google Cloud Storage?
We're trying to get an audiofile from Google Text-to-Speech and save it to Firebase Storage, using a Google Cloud Function.我们正在尝试使用 Google Cloud Function 从 Google Text-to-Speech 获取音频文件并将其保存到 Firebase Storage。 The documentation for Google Text-to-Speech show how to get an audiofile and save it locally: Google Text-to-Speech 的文档展示了如何获取音频文件并将其保存在本地:
// 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');
This results in an error message Error: EROFS: read-only file system
.这会导致错误消息Error: EROFS: read-only file system
。 Google Cloud Storage doesn't allow writing files locally. Google Cloud Storage 不允许在本地写入文件。
Using Firebase Storage bucket.upload()
has a few problems:使用 Firebase Storage bucket.upload()
有几个问题:
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
));
The error message is TypeError: Path must be a string
.错误消息是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.
bucket.upload()
的第一个参数是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.并且应该是一个字符串,所以response.audioContent
不起作用。
The documentation for bucket.upload()
suggests that destination: destinationPath
is where we should put the path to the Firebase Storage location. bucket.upload()
的文档建议destination: destinationPath
是我们应该放置 Firebase 存储位置路径的地方。 Is this correct?这样对吗?
How do we take the audiofile from Google Text-to-Speech ( response.audioContent
) and save it as a string that bucket.upload()
can access?我们如何从 Google Text-to-Speech ( response.audioContent
) 获取bucket.upload()
并将其保存为bucket.upload()
可以访问的字符串? Or should we use something else instead of bucket.upload()
?或者我们应该使用其他东西而不是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()
was the answer. file.save()
就是答案。 util.promisify
was unnecessary, and causes an error message about original
something. util.promisify
是不必要的,并导致有关original
内容的错误消息。 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
We're getting an error TypeError: [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type function at Object.promisify
.我们收到一个错误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.此错误似乎不会影响云功能。
To reiterate the stuff that didn't work, fs.createWriteStream
didn't work because Google Cloud Functions can't handle Node file system commands.重申无效的内容, fs.createWriteStream
无效,因为 Google Cloud Functions 无法处理Node 文件系统命令。 Instead, Google Cloud Functions have their own methods that wrap the Node file system commands.相反,Google Cloud Functions 有自己的方法来包装 Node 文件系统命令。 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. bucket.upload()会将本地文件上传到存储桶,但本地文件的路径必须是字符串,而不是缓冲区或来自 API 的流。 file.save() is documented as file.save()记录为
Write arbitrary data to a file.将任意数据写入文件。
This is a convenience method which wraps
File#createWriteStream
.这是一种包装File#createWriteStream
的便捷方法。
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.之后,我们只需要理顺contentType
( audio/mpeg
,而不是mp3
)和文件路径。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.