Skip to content

Commit 7eb8719

Browse files
crowdusbusunkim96
authored andcommitted
fix: MP3 file test for Text-to-Speech SSML addresses [(#2378)](GoogleCloudPlatform/python-docs-samples#2378)
* fix: refactored MP3 file tests * fix: moving resources to cloud-client/resources * fix: removing expected_example.mp3
1 parent fb964a8 commit 7eb8719

File tree

4 files changed

+168
-0
lines changed

4 files changed

+168
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<speak>123 Street Ln, Small Town, IL 12345 USA
2+
<break time="2s"/>1 Jenny St &amp; Number St, Tutone City, CA 86753
3+
<break time="2s"/>1 Piazza del Fibonacci, 12358 Pisa, Italy
4+
<break time="2s"/></speak>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
123 Street Ln, Small Town, IL 12345 USA
2+
1 Jenny St & Number St, Tutone City, CA 86753
3+
1 Piazza del Fibonacci, 12358 Pisa, Italy
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
# [START tts_ssml_address_imports]
17+
from google.cloud import texttospeech
18+
19+
import html
20+
# [END tts_ssml_address_imports]
21+
22+
23+
# [START tts_ssml_address_audio]
24+
def ssml_to_audio(ssml_text, outfile):
25+
# Generates SSML text from plaintext.
26+
#
27+
# Given a string of SSML text and an output file name, this function
28+
# calls the Text-to-Speech API. The API returns a synthetic audio
29+
# version of the text, formatted according to the SSML commands. This
30+
# function saves the synthetic audio to the designated output file.
31+
#
32+
# Args:
33+
# ssml_text: string of SSML text
34+
# outfile: string name of file under which to save audio output
35+
#
36+
# Returns:
37+
# nothing
38+
39+
# Instantiates a client
40+
client = texttospeech.TextToSpeechClient()
41+
42+
# Sets the text input to be synthesized
43+
synthesis_input = texttospeech.types.SynthesisInput(ssml=ssml_text)
44+
45+
# Builds the voice request, selects the language code ("en-US") and
46+
# the SSML voice gender ("MALE")
47+
voice = texttospeech.types.VoiceSelectionParams(
48+
language_code='en-US',
49+
ssml_gender=texttospeech.enums.SsmlVoiceGender.MALE)
50+
51+
# Selects the type of audio file to return
52+
audio_config = texttospeech.types.AudioConfig(
53+
audio_encoding=texttospeech.enums.AudioEncoding.MP3)
54+
55+
# Performs the text-to-speech request on the text input with the selected
56+
# voice parameters and audio file type
57+
response = client.synthesize_speech(synthesis_input, voice, audio_config)
58+
59+
# Writes the synthetic audio to the output file.
60+
with open(outfile, 'wb') as out:
61+
out.write(response.audio_content)
62+
print('Audio content written to file ' + outfile)
63+
# [END tts_ssml_address_audio]
64+
65+
66+
# [START tts_ssml_address_ssml]
67+
def text_to_ssml(inputfile):
68+
# Generates SSML text from plaintext.
69+
# Given an input filename, this function converts the contents of the text
70+
# file into a string of formatted SSML text. This function formats the SSML
71+
# string so that, when synthesized, the synthetic audio will pause for two
72+
# seconds between each line of the text file. This function also handles
73+
# special text characters which might interfere with SSML commands.
74+
#
75+
# Args:
76+
# inputfile: string name of plaintext file
77+
#
78+
# Returns:
79+
# A string of SSML text based on plaintext input
80+
81+
# Parses lines of input file
82+
with open(inputfile, 'r') as f:
83+
raw_lines = f.read()
84+
85+
# Replace special characters with HTML Ampersand Character Codes
86+
# These Codes prevent the API from confusing text with
87+
# SSML commands
88+
# For example, '<' --> '&lt;' and '&' --> '&amp;'
89+
90+
escaped_lines = html.escape(raw_lines)
91+
92+
# Convert plaintext to SSML
93+
# Wait two seconds between each address
94+
ssml = '<speak>{}</speak>'.format(
95+
escaped_lines.replace('\n', '\n<break time="2s"/>'))
96+
97+
# Return the concatenated string of ssml script
98+
return ssml
99+
# [END tts_ssml_address_ssml]
100+
101+
102+
# [START tts_ssml_address_test]
103+
def main():
104+
# test example address file
105+
plaintext = 'resources/example.txt'
106+
ssml_text = text_to_ssml(plaintext)
107+
ssml_to_audio(ssml_text, 'resources/example.mp3')
108+
# [END tts_ssml_address_test]
109+
110+
111+
if __name__ == '__main__':
112+
main()
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from ssml_addresses import text_to_ssml
16+
from ssml_addresses import ssml_to_audio
17+
18+
import filecmp
19+
import os
20+
21+
22+
def test_text_to_ssml(capsys):
23+
24+
# Read expected SSML output from resources
25+
with open('resources/example.ssml', 'r') as f:
26+
expected_ssml = f.read()
27+
28+
# Assert plaintext converted to SSML
29+
input_text = 'resources/example.txt'
30+
tested_ssml = text_to_ssml(input_text)
31+
assert expected_ssml == tested_ssml
32+
33+
34+
def test_ssml_to_audio(capsys):
35+
36+
# Read SSML input from resources
37+
with open('resources/example.ssml', 'r') as f:
38+
input_ssml = f.read()
39+
40+
# Assert audio file generated
41+
ssml_to_audio(input_ssml, 'test_example.mp3')
42+
out, err = capsys.readouterr()
43+
44+
# Assert MP3 file created
45+
assert os.path.isfile('test_example.mp3')
46+
assert "Audio content written to file test_example.mp3" in out
47+
48+
# Delete MP3 test file
49+
os.remove("test_example.mp3")

0 commit comments

Comments
 (0)