Skip to content

Commit

Permalink
feat: code samples for ssml addresses tutorial (#257)
Browse files Browse the repository at this point in the history
* feat: code samples for ssml addresses tutorial

* fix: lint

* fix: lint

* fix: lint

* fix: debugging delete example.mp3 file

* fix: mp3 test file deletion

* fix: refactored tests

* fix: region tag formatting for main

* wrapping main
  • Loading branch information
crowdus authored and leahecole committed Sep 5, 2019
1 parent fb5ac72 commit a2c6dd8
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 0 deletions.
4 changes: 4 additions & 0 deletions texttospeech/resources/example.ssml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<speak>123 Street Ln, Small Town, IL 12345 USA
<break time="2s"/>1 Jenny St &amp; Number St, Tutone City, CA 86753
<break time="2s"/>1 Piazza del Fibonacci, 12358 Pisa, Italy
<break time="2s"/></speak>
3 changes: 3 additions & 0 deletions texttospeech/resources/example.txt
Original file line number Diff line number Diff line change
@@ -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
Binary file added texttospeech/resources/expected_example.mp3
Binary file not shown.
127 changes: 127 additions & 0 deletions texttospeech/ssmlAddresses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* 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, '<' --> '&lt;' and '&' --> '&amp;'
let escapedLines = rawLines;
escapedLines = escapedLines.replace(/&/g, '&amp;');
escapedLines = escapedLines.replace(/"/g, '&quot;');
escapedLines = escapedLines.replace(/</g, '&lt;');
escapedLines = escapedLines.replace(/>/g, '&gt;');

// Convert plaintext to SSML
// Tag SSML so that there is a 2 second pause between each address
const expandedNewline = escapedLines.replace(/\n/g, '\n<break time="2s"/>');
const ssml = '<speak>' + expandedNewline + '</speak>';

// 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));
52 changes: 52 additions & 0 deletions texttospeech/test/ssmlAddresses.test.js
Original file line number Diff line number Diff line change
@@ -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 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(function() {
try {
fs.unlinkSync(outputFile);
} catch (e) {
// don't throw an exception
}
});

// delete 'resources/example.mp3' file
after(function() {
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);
});
});

0 comments on commit a2c6dd8

Please sign in to comment.