diff --git a/.github/workflows/texttospeech.yaml b/.github/workflows/texttospeech.yaml
new file mode 100644
index 0000000000..39cd82f5ad
--- /dev/null
+++ b/.github/workflows/texttospeech.yaml
@@ -0,0 +1,68 @@
+name: texttospeech
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - 'texttospeech/**'
+ pull_request:
+ paths:
+ - 'texttospeech/**'
+ pull_request_target:
+ types: [labeled]
+ paths:
+ - 'texttospeech/**'
+ schedule:
+ - cron: '0 0 * * 0'
+jobs:
+ test:
+ if: ${{ github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' }}
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ permissions:
+ contents: 'write'
+ pull-requests: 'write'
+ id-token: 'write'
+ steps:
+ - uses: actions/checkout@v3.1.0
+ with:
+ ref: ${{github.event.pull_request.head.sha}}
+ - uses: 'google-github-actions/auth@v1.0.0'
+ with:
+ workload_identity_provider: 'projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider'
+ service_account: 'kokoro-system-test@long-door-651.iam.gserviceaccount.com'
+ create_credentials_file: 'true'
+ access_token_lifetime: 600s
+ - uses: actions/setup-node@v3.5.1
+ with:
+ node-version: 16
+ - run: npm install
+ working-directory: texttospeech
+ - run: npm test
+ working-directory: texttospeech
+ env:
+ MOCHA_REPORTER_SUITENAME: texttospeech
+ MOCHA_REPORTER_OUTPUT: texttospeech_sponge_log.xml
+ MOCHA_REPORTER: xunit
+ - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'actions:force-run' }}
+ uses: actions/github-script@v6
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ try {
+ await github.rest.issues.removeLabel({
+ name: 'actions:force-run',
+ owner: 'GoogleCloudPlatform',
+ repo: 'nodejs-docs-samples',
+ issue_number: context.payload.pull_request.number
+ });
+ } catch (e) {
+ if (!e.message.includes('Label does not exist')) {
+ throw e;
+ }
+ }
+ - if: ${{ github.event_name == 'schedule'}}
+ run: |
+ curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L
+ chmod +x ./flakybot
+ ./flakybot --repo GoogleCloudPlatform/nodejs-docs-samples --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}
diff --git a/.github/workflows/workflows.json b/.github/workflows/workflows.json
index e3c110eeed..fa274e2139 100644
--- a/.github/workflows/workflows.json
+++ b/.github/workflows/workflows.json
@@ -61,6 +61,7 @@
"scheduler",
"speech",
"talent",
+ "texttospeech",
"translate",
"video-intelligence",
"contact-center-insights",
diff --git a/CODEOWNERS b/CODEOWNERS
index f973e3bb0d..ab1bb75f7e 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -42,7 +42,14 @@ monitoring/opencensus @GoogleCloudPlatform/nodejs-samples-reviewers
# Data & AI
contact-center-insights @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
+datalabeling @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
+document-ai @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
+mediatranslation @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
+speech @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
talent @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
+texttospeech @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
+translate @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
+video-intelligence @GoogleCloudPlatform/dee-data-ai @GoogleCloudPlatform/nodejs-samples-reviewers
# DEE-PO
error-reporting @GoogleCloudPlatform/dee-platform-ops @GoogleCloudPlatform/nodejs-samples-reviewers
\ No newline at end of file
diff --git a/texttospeech/.eslintrc.yml b/texttospeech/.eslintrc.yml
new file mode 100644
index 0000000000..282535f55f
--- /dev/null
+++ b/texttospeech/.eslintrc.yml
@@ -0,0 +1,3 @@
+---
+rules:
+ no-console: off
diff --git a/texttospeech/audioProfile.js b/texttospeech/audioProfile.js
new file mode 100644
index 0000000000..c991f33f61
--- /dev/null
+++ b/texttospeech/audioProfile.js
@@ -0,0 +1,65 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+async function main(
+ text = 'Hello Everybody! This is an audio profile optimized sound byte.',
+ outputFile = './resources/phone.mp3',
+ languageCode = 'en-US',
+ ssmlGender = 'FEMALE'
+) {
+ //[START tts_synthesize_text_audio_profile]
+
+ /**
+ * TODO(developer): Uncomment these variables before running the sample.
+ */
+ // const text = 'Text you want to vocalize';
+ // const outputFile = 'YOUR_OUTPUT_FILE_LOCAtION;
+ // const languageCode = 'LANGUAGE_CODE_FOR_OUTPUT';
+ // const ssmlGender = 'SSML_GENDER_OF_SPEAKER';
+
+ // Imports the Google Cloud client library
+ const speech = require('@google-cloud/text-to-speech');
+ const fs = require('fs');
+ const util = require('util');
+
+ // Creates a client
+ const client = new speech.TextToSpeechClient();
+
+ async function synthesizeWithEffectsProfile() {
+ // Add one or more effects profiles to array.
+ // Refer to documentation for more details:
+ // https://cloud.google.com/text-to-speech/docs/audio-profiles
+ const effectsProfileId = ['telephony-class-application'];
+
+ const request = {
+ input: {text: text},
+ voice: {languageCode: languageCode, ssmlGender: ssmlGender},
+ audioConfig: {audioEncoding: 'MP3', effectsProfileId: effectsProfileId},
+ };
+
+ const [response] = await client.synthesizeSpeech(request);
+ const writeFile = util.promisify(fs.writeFile);
+ await writeFile(outputFile, response.audioContent, 'binary');
+ console.log(`Audio content written to file: ${outputFile}`);
+ }
+ // [END tts_synthesize_text_audio_profile]
+
+ synthesizeWithEffectsProfile();
+}
+
+main(...process.argv.slice(2)).catch(err => {
+ console.error(err);
+ process.exitCode = 1;
+});
diff --git a/texttospeech/hello.mp3 b/texttospeech/hello.mp3
new file mode 100644
index 0000000000..726773ed65
Binary files /dev/null and b/texttospeech/hello.mp3 differ
diff --git a/texttospeech/listVoices.js b/texttospeech/listVoices.js
new file mode 100644
index 0000000000..84792d2ab0
--- /dev/null
+++ b/texttospeech/listVoices.js
@@ -0,0 +1,53 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+async function listVoices() {
+ // [START tts_list_voices]
+ const textToSpeech = require('@google-cloud/text-to-speech');
+
+ const client = new textToSpeech.TextToSpeechClient();
+
+ const [result] = await client.listVoices({});
+ const voices = result.voices;
+
+ console.log('Voices:');
+ voices.forEach(voice => {
+ console.log(`Name: ${voice.name}`);
+ console.log(` SSML Voice Gender: ${voice.ssmlGender}`);
+ console.log(` Natural Sample Rate Hertz: ${voice.naturalSampleRateHertz}`);
+ console.log(' Supported languages:');
+ voice.languageCodes.forEach(languageCode => {
+ console.log(` ${languageCode}`);
+ });
+ });
+ // [END tts_list_voices]
+}
+
+async function main() {
+require(`yargs`) // eslint-disable-line
+ .demand(1)
+ .command('list-voices', 'List supported voices.', {}, () => listVoices())
+ .example('node $0 list-voices')
+ .wrap(120)
+ .recommendCommands()
+ .epilogue(
+ 'For more information, see https://cloud.google.com/text-to-speech/docs'
+ )
+ .help()
+ .strict().argv;
+}
+
+main().catch(console.error);
diff --git a/texttospeech/package.json b/texttospeech/package.json
new file mode 100644
index 0000000000..4af1875f74
--- /dev/null
+++ b/texttospeech/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "nodejs-docs-samples-text-to-speech",
+ "private": true,
+ "license": "Apache-2.0",
+ "author": "Google Inc.",
+ "repository": "googleapis/nodejs-text-to-speech",
+ "files": [
+ "*.js"
+ ],
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "scripts": {
+ "test": "mocha --timeout=60000"
+ },
+ "dependencies": {
+ "@google-cloud/text-to-speech": "^4.0.4",
+ "yargs": "^16.0.0"
+ },
+ "devDependencies": {
+ "chai": "^4.2.0",
+ "mocha": "^8.0.0"
+ }
+}
diff --git a/texttospeech/quickstart.js b/texttospeech/quickstart.js
new file mode 100644
index 0000000000..92718a9a98
--- /dev/null
+++ b/texttospeech/quickstart.js
@@ -0,0 +1,51 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+function main() {
+ // [START tts_quickstart]
+ // Imports the Google Cloud client library
+ const textToSpeech = require('@google-cloud/text-to-speech');
+
+ // Import other required libraries
+ const fs = require('fs');
+ const util = require('util');
+ // Creates a client
+ const client = new textToSpeech.TextToSpeechClient();
+ async function quickStart() {
+ // The text to synthesize
+ const text = 'hello, world!';
+
+ // Construct the request
+ const request = {
+ input: {text: text},
+ // Select the language and SSML voice gender (optional)
+ voice: {languageCode: 'en-US', ssmlGender: 'NEUTRAL'},
+ // select the type of audio encoding
+ audioConfig: {audioEncoding: 'MP3'},
+ };
+
+ // 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');
+ }
+ quickStart();
+ // [END tts_quickstart]
+}
+
+main(...process.argv.slice(2));
diff --git a/texttospeech/resources/example.ssml b/texttospeech/resources/example.ssml
new file mode 100644
index 0000000000..1e20716f0d
--- /dev/null
+++ b/texttospeech/resources/example.ssml
@@ -0,0 +1,4 @@
+123 Street Ln, Small Town, IL 12345 USA
+1 Jenny St & Number St, Tutone City, CA 86753
+1 Piazza del Fibonacci, 12358 Pisa, Italy
+
\ No newline at end of file
diff --git a/texttospeech/resources/example.txt b/texttospeech/resources/example.txt
new file mode 100644
index 0000000000..9cd7d74db3
--- /dev/null
+++ b/texttospeech/resources/example.txt
@@ -0,0 +1,3 @@
+123 Street Ln, Small Town, IL 12345 USA
+1 Jenny St & Number St, Tutone City, CA 86753
+1 Piazza del Fibonacci, 12358 Pisa, Italy
diff --git a/texttospeech/resources/expected_example.mp3 b/texttospeech/resources/expected_example.mp3
new file mode 100644
index 0000000000..2e4f7f2f6e
Binary files /dev/null and b/texttospeech/resources/expected_example.mp3 differ
diff --git a/texttospeech/resources/hello.ssml b/texttospeech/resources/hello.ssml
new file mode 100644
index 0000000000..df7bf9eee3
--- /dev/null
+++ b/texttospeech/resources/hello.ssml
@@ -0,0 +1 @@
+Hello there.
diff --git a/texttospeech/resources/hello.txt b/texttospeech/resources/hello.txt
new file mode 100644
index 0000000000..c12abce9f3
--- /dev/null
+++ b/texttospeech/resources/hello.txt
@@ -0,0 +1 @@
+Hello there.
diff --git a/texttospeech/ssmlAddresses.js b/texttospeech/ssmlAddresses.js
new file mode 100644
index 0000000000..26caf86539
--- /dev/null
+++ b/texttospeech/ssmlAddresses.js
@@ -0,0 +1,126 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+function main(
+ inFile = 'resources/example.txt',
+ outFile = 'resources/example.mp3'
+) {
+ // [START tts_ssml_address_test]
+ /**
+ * TODO (developer): Uncomment these variables before running the sample
+ *
+ */
+ // inFile = 'resources/example.txt',
+ // outFile = 'resources/example.mp3'
+ // [START tts_ssml_address_imports]
+ // Imports the Google Cloud client library
+ const textToSpeech = require('@google-cloud/text-to-speech');
+
+ // Import other required libraries
+ const fs = require('fs');
+ //const escape = require('escape-html');
+ const util = require('util');
+ // [END tts_ssml_address_imports]
+
+ // [START tts_ssml_address_audio]
+ /**
+ * Generates synthetic audio from a String of SSML text.
+ *
+ * Given a string of SSML text and an output file name, this function
+ * calls the Text-to-Speech API. The API returns a synthetic audio
+ * version of the text, formatted according to the SSML commands. This
+ * function saves the synthetic audio to the designated output file.
+ *
+ * ARGS
+ * ssmlText: String of tagged SSML text
+ * outfile: String name of file under which to save audio output
+ * RETURNS
+ * nothing
+ *
+ */
+ async function ssmlToAudio(ssmlText, outFile) {
+ // Creates a client
+ const client = new textToSpeech.TextToSpeechClient();
+
+ // Constructs the request
+ const request = {
+ // Select the text to synthesize
+ input: {ssml: ssmlText},
+ // Select the language and SSML Voice Gender (optional)
+ voice: {languageCode: 'en-US', ssmlGender: 'MALE'},
+ // Select the type of audio encoding
+ audioConfig: {audioEncoding: 'MP3'},
+ };
+
+ // 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(outFile, response.audioContent, 'binary');
+ console.log('Audio content written to file ' + outFile);
+ }
+ // [END tts_ssml_address_audio]
+
+ // [START tts_ssml_address_ssml]
+ /**
+ * Generates SSML text from plaintext.
+ *
+ * Given an input filename, this function converts the contents of the input text file
+ * into a String of tagged SSML text. This function formats the SSML String so that,
+ * when synthesized, the synthetic audio will pause for two seconds between each line
+ * of the text file. This function also handles special text characters which might
+ * interfere with SSML commands.
+ *
+ * ARGS
+ * inputfile: String name of plaintext file
+ * RETURNS
+ * a String of SSML text based on plaintext input
+ *
+ */
+ function textToSsml(inputFile) {
+ let rawLines = '';
+ // Read input file
+ try {
+ rawLines = fs.readFileSync(inputFile, 'utf8');
+ } catch (e) {
+ console.log('Error:', e.stack);
+ return;
+ }
+
+ // Replace special characters with HTML Ampersand Character Codes
+ // These codes prevent the API from confusing text with SSML tags
+ // For example, '<' --> '<' and '&' --> '&'
+ let escapedLines = rawLines;
+ escapedLines = escapedLines.replace(/&/g, '&');
+ escapedLines = escapedLines.replace(/"/g, '"');
+ escapedLines = escapedLines.replace(//g, '>');
+
+ // Convert plaintext to SSML
+ // Tag SSML so that there is a 2 second pause between each address
+ const expandedNewline = escapedLines.replace(/\n/g, '\n');
+ const ssml = '' + expandedNewline + '';
+
+ // Return the concatenated String of SSML
+ return ssml;
+ }
+ // [END tts_ssml_address_ssml]
+ const ssml = textToSsml(inFile);
+ ssmlToAudio(ssml, outFile);
+ // [END tts_ssml_address_test]
+}
+
+main(...process.argv.slice(2));
diff --git a/texttospeech/synthesize.js b/texttospeech/synthesize.js
new file mode 100644
index 0000000000..8344d7193c
--- /dev/null
+++ b/texttospeech/synthesize.js
@@ -0,0 +1,166 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+async function synthesizeText(text, outputFile) {
+ // [START tts_synthesize_text]
+ const textToSpeech = require('@google-cloud/text-to-speech');
+ const fs = require('fs');
+ const util = require('util');
+
+ const client = new textToSpeech.TextToSpeechClient();
+
+ /**
+ * TODO(developer): Uncomment the following lines before running the sample.
+ */
+ // const text = 'Text to synthesize, eg. hello';
+ // const outputFile = 'Local path to save audio file to, e.g. output.mp3';
+
+ const request = {
+ input: {text: text},
+ voice: {languageCode: 'en-US', ssmlGender: 'FEMALE'},
+ audioConfig: {audioEncoding: 'MP3'},
+ };
+ const [response] = await client.synthesizeSpeech(request);
+ const writeFile = util.promisify(fs.writeFile);
+ await writeFile(outputFile, response.audioContent, 'binary');
+ console.log(`Audio content written to file: ${outputFile}`);
+ // [END tts_synthesize_text]
+}
+
+async function synthesizeSsml(ssml, outputFile) {
+ // [START tts_synthesize_ssml]
+ const textToSpeech = require('@google-cloud/text-to-speech');
+ const fs = require('fs');
+ const util = require('util');
+
+ const client = new textToSpeech.TextToSpeechClient();
+
+ /**
+ * TODO(developer): Uncomment the following lines before running the sample.
+ */
+ // const ssml = 'Hello there.';
+ // const outputFile = 'Local path to save audio file to, e.g. output.mp3';
+
+ const request = {
+ input: {ssml: ssml},
+ voice: {languageCode: 'en-US', ssmlGender: 'FEMALE'},
+ audioConfig: {audioEncoding: 'MP3'},
+ };
+
+ const [response] = await client.synthesizeSpeech(request);
+ const writeFile = util.promisify(fs.writeFile);
+ await writeFile(outputFile, response.audioContent, 'binary');
+ console.log(`Audio content written to file: ${outputFile}`);
+ // [END tts_synthesize_ssml]
+}
+
+async function synthesizeTextFile(textFile, outputFile) {
+ // [START tts_synthesize_text_file]
+ const textToSpeech = require('@google-cloud/text-to-speech');
+ const fs = require('fs');
+ const util = require('util');
+
+ const client = new textToSpeech.TextToSpeechClient();
+
+ /**
+ * TODO(developer): Uncomment the following lines before running the sample.
+ */
+ // const textFile = 'Local path to text file, eg. input.txt';
+ // const outputFile = 'Local path to save audio file to, e.g. output.mp3';
+
+ const request = {
+ input: {text: fs.readFileSync(textFile)},
+ voice: {languageCode: 'en-US', ssmlGender: 'FEMALE'},
+ audioConfig: {audioEncoding: 'MP3'},
+ };
+
+ const [response] = await client.synthesizeSpeech(request);
+ const writeFile = util.promisify(fs.writeFile);
+ await writeFile(outputFile, response.audioContent, 'binary');
+ console.log(`Audio content written to file: ${outputFile}`);
+ // [END tts_synthesize_text_file]
+}
+
+async function synthesizeSsmlFile(ssmlFile, outputFile) {
+ // [START tts_synthesize_ssml_file]
+ const textToSpeech = require('@google-cloud/text-to-speech');
+ const fs = require('fs');
+ const util = require('util');
+
+ const client = new textToSpeech.TextToSpeechClient();
+
+ /**
+ * TODO(developer): Uncomment the following lines before running the sample.
+ */
+ // const ssmlFile = 'Local path to SSML file, eg. input.ssml';
+ // const outputFile = 'Local path to save audio file to, e.g. output.mp3';
+
+ const request = {
+ input: {ssml: fs.readFileSync(ssmlFile)},
+ voice: {languageCode: 'en-US', ssmlGender: 'FEMALE'},
+ audioConfig: {audioEncoding: 'MP3'},
+ };
+
+ const [response] = await client.synthesizeSpeech(request);
+ const writeFile = util.promisify(fs.writeFile);
+ await writeFile(outputFile, response.audioContent, 'binary');
+ console.log(`Audio content written to file: ${outputFile}`);
+ // [END tts_synthesize_ssml_file]
+}
+
+async function main() {
+require(`yargs`) // eslint-disable-line
+ .demand(1)
+ .command('text ', 'Synthesizes audio file from text', {}, opts =>
+ synthesizeText(opts.text, opts.outputFile)
+ )
+ .command('ssml ', 'Synthesizes audio file from SSML', {}, opts =>
+ synthesizeSsml(opts.ssml, opts.outputFile)
+ )
+ .command(
+ 'text-file ',
+ 'Synthesizes audio file from text in a file',
+ {},
+ opts => synthesizeTextFile(opts.textFile, opts.outputFile)
+ )
+ .command(
+ 'ssml-file ',
+ 'Synthesizes audio file from SSML in a file',
+ {},
+ opts => synthesizeSsmlFile(opts.ssmlFile, opts.outputFile)
+ )
+ .options({
+ outputFile: {
+ alias: 'o',
+ default: 'output.mp3',
+ global: true,
+ requiresArg: true,
+ type: 'string',
+ },
+ })
+ .example('node $0 text "hello" -o hello.mp3')
+ .example('node $0 ssml "Hello there." -o hello.mp3')
+ .example('node $0 text-file resources/hello.txt -o output.mp3')
+ .example('node $0 ssml-file resources/hello.ssml -o output.mp3')
+ .wrap(120)
+ .recommendCommands()
+ .epilogue(
+ 'For more information, see https://cloud.google.com/text-to-speech/docs'
+ )
+ .help()
+ .strict().argv;
+}
+
+main().catch(console.error);
diff --git a/texttospeech/test/.eslintrc.yml b/texttospeech/test/.eslintrc.yml
new file mode 100644
index 0000000000..ed97d539c0
--- /dev/null
+++ b/texttospeech/test/.eslintrc.yml
@@ -0,0 +1 @@
+---
diff --git a/texttospeech/test/audioProfile.test.js b/texttospeech/test/audioProfile.test.js
new file mode 100644
index 0000000000..44069e0691
--- /dev/null
+++ b/texttospeech/test/audioProfile.test.js
@@ -0,0 +1,47 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+const fs = require('fs');
+const {assert} = require('chai');
+const {describe, it, after} = require('mocha');
+const cp = require('child_process');
+
+const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});
+
+const cmd = 'node audioProfile.js';
+const text =
+ '"Hello Everybody! This is an Audio Profile Optimized Sound Byte."';
+const outputFile = 'phonetest.mp3';
+
+describe('audio profile', () => {
+ after(() => {
+ function unlink(outputFile) {
+ try {
+ fs.unlinkSync(outputFile);
+ } catch (err) {
+ // Ignore error
+ }
+ }
+ [outputFile].map(unlink);
+ });
+
+ it('should synthesize human audio using hardware profile', async () => {
+ assert.strictEqual(fs.existsSync(outputFile), false);
+ const output = execSync(`${cmd} ${text} ${outputFile}`);
+ assert.match(output, new RegExp('Audio content written to file:'));
+ assert.ok(fs.existsSync(outputFile));
+ });
+});
diff --git a/texttospeech/test/listVoices.test.js b/texttospeech/test/listVoices.test.js
new file mode 100644
index 0000000000..7af1e9579e
--- /dev/null
+++ b/texttospeech/test/listVoices.test.js
@@ -0,0 +1,31 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+const {assert} = require('chai');
+const {describe, it} = require('mocha');
+const cp = require('child_process');
+
+const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});
+
+const cmd = 'node listVoices.js';
+
+describe('list voices', () => {
+ it('should list voices', async () => {
+ const stdout = execSync(`${cmd} list-voices`);
+ assert.match(stdout, /SSML Voice Gender: FEMALE/);
+ assert.match(stdout, /Natural Sample Rate Hertz: 24000/);
+ });
+});
diff --git a/texttospeech/test/quickstart.test.js b/texttospeech/test/quickstart.test.js
new file mode 100644
index 0000000000..cd1460c7b5
--- /dev/null
+++ b/texttospeech/test/quickstart.test.js
@@ -0,0 +1,41 @@
+// Copyright 2017 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+const fs = require('fs');
+const {assert} = require('chai');
+const {describe, it, after} = require('mocha');
+const cp = require('child_process');
+
+const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});
+
+const outputFile = 'output.mp3';
+
+describe('quickstart', () => {
+ after(() => {
+ try {
+ fs.unlinkSync(outputFile);
+ } catch (err) {
+ // Ignore error
+ }
+ });
+
+ it('should synthesize speech to local mp3 file', () => {
+ assert.strictEqual(fs.existsSync(outputFile), false);
+ const stdout = execSync('node quickstart');
+ assert.match(stdout, /Audio content written to file: output.mp3/);
+ assert.ok(fs.existsSync(outputFile));
+ });
+});
diff --git a/texttospeech/test/ssmlAddresses.test.js b/texttospeech/test/ssmlAddresses.test.js
new file mode 100644
index 0000000000..beaa932150
--- /dev/null
+++ b/texttospeech/test/ssmlAddresses.test.js
@@ -0,0 +1,52 @@
+// Copyright 2019 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+const fs = require('fs');
+const {assert} = require('chai');
+const {describe, it, before, after} = require('mocha');
+const cp = require('child_process');
+
+const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});
+
+const cmd = 'node ssmlAddresses.js';
+const outputFile = 'resources/example.mp3';
+
+describe('ssmlAddresses', () => {
+ // delete 'resources/example.mp3' file if it already exists
+ before(() => {
+ try {
+ fs.unlinkSync(outputFile);
+ } catch (e) {
+ // don't throw an exception
+ }
+ });
+
+ // delete 'resources/example.mp3' file
+ after(() => {
+ fs.unlinkSync(outputFile);
+ assert.strictEqual(fs.existsSync(outputFile), false);
+ });
+
+ it('synthesize speech to local mp3 file', async () => {
+ assert.strictEqual(fs.existsSync(outputFile), false);
+ const stdout = execSync(`${cmd}`);
+ assert.match(
+ stdout,
+ /Audio content written to file resources\/example.mp3/
+ );
+ assert.strictEqual(fs.existsSync(outputFile), true);
+ });
+});
diff --git a/texttospeech/test/synthesize.test.js b/texttospeech/test/synthesize.test.js
new file mode 100644
index 0000000000..ad50a48547
--- /dev/null
+++ b/texttospeech/test/synthesize.test.js
@@ -0,0 +1,88 @@
+// Copyright 2018 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+'use strict';
+
+const fs = require('fs');
+const path = require('path');
+const {assert} = require('chai');
+const {describe, it, afterEach} = require('mocha');
+const cp = require('child_process');
+
+const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});
+
+const cmd = 'node synthesize.js';
+const text = 'Hello there.';
+const ssml = 'Hello there.';
+const outputFile = 'test-output.mp3';
+const files = ['hello.txt', 'hello.ssml'].map(name => {
+ return {
+ name,
+ localPath: path.resolve(path.join(__dirname, `../resources/${name}`)),
+ };
+});
+
+describe('synthesize', () => {
+ afterEach(() => {
+ try {
+ fs.unlinkSync(outputFile);
+ } catch (err) {
+ // Ignore error
+ }
+ });
+
+ it('should synthesize audio from text', async () => {
+ assert.strictEqual(fs.existsSync(outputFile), false);
+ const output = execSync(`${cmd} text '${text}' --outputFile ${outputFile}`);
+ assert.match(
+ output,
+ new RegExp(`Audio content written to file: ${outputFile}`)
+ );
+ assert.ok(fs.existsSync(outputFile));
+ });
+
+ it('should synthesize audio from ssml', async () => {
+ assert.strictEqual(fs.existsSync(outputFile), false);
+ const output = execSync(`${cmd} ssml "${ssml}" --outputFile ${outputFile}`);
+ assert.match(
+ output,
+ new RegExp(`Audio content written to file: ${outputFile}`)
+ );
+ assert.ok(fs.existsSync(outputFile));
+ });
+
+ it('should synthesize audio from text file', async () => {
+ assert.strictEqual(fs.existsSync(outputFile), false);
+ const output = execSync(
+ `${cmd} text-file ${files[0].localPath} --outputFile ${outputFile}`
+ );
+ assert.match(
+ output,
+ new RegExp(`Audio content written to file: ${outputFile}`)
+ );
+ assert.ok(fs.existsSync(outputFile));
+ });
+
+ it('should synthesize audio from ssml file', async () => {
+ assert.strictEqual(fs.existsSync(outputFile), false);
+ const output = execSync(
+ `${cmd} ssml-file ${files[1].localPath} --outputFile ${outputFile}`
+ );
+ assert.match(
+ output,
+ new RegExp(`Audio content written to file: ${outputFile}`)
+ );
+ assert.ok(fs.existsSync(outputFile));
+ });
+});