2

Want to nest "Say" instructions inside a gather, but I want to use modifiers like .Emphasis, .Break, and .Prosody on the "Say" instructions. There does not seem to be a way to do this in C#. The resulting TwiML code I want would look like this:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="/voice/processmygather" method="GET">
<Say> Hi
<break strength="x-weak" time="100ms"/>
<emphasis level="moderate">Words to emphasize</emphasis>
<p>Words to speak</p>
<prosody pitch="-10%" rate="85%" volume="-6dB">Words to speak</prosody>
<s>Words to speak</s>
<say-as interpret-as="spell-out">Words to speak</say-as>
<sub alias="alias">Words to be substituted</sub>
<w>Words to speak</w>
</Say>
</Gather>
<Say>We didn't receive any input. Goodbye!</Say>
</Response>

In C#, I can create a "Say" verb object and modify it to look like the above, but cannot arrange it as nested within a gather so that the user could interrupt the say with a response and move on to processing the gather.

var response = new VoiceResponse();
var mygather = new Gather(input: bothDtmfAndSpeech,
                action: new Uri("/voice/processmygather", UriKind.Relative),
                speechModel: Gather.SpeechModelEnum.NumbersAndCommands,
                enhanced: true,
                hints: hintchoices,
                bargeIn: true,
                speechTimeout: "auto",
                numDigits: 1);
var mysay = new Say("Hi", voice: "Polly.Joanna");
mysay.Break(strength: "x-weak", time: "100ms");
mysay.Emphasis("Words to emphasize", level: "moderate");
mysay.P("Words to speak");
mysay.Phoneme("Words to speak", alphabet: "x-sampa", ph: "pɪˈkɑːn");
mysay.Prosody("Words to speak", pitch: "-10%", rate: "85%", volume: "-6dB");
mysay.SayAs("Words to speak", interpretAs: "spell-out", role: "yyyymmdd");

/* There seems to be no way to do the following command */
response.Append(mygather.mysay);

/* I can only do the following */
response.Append(mysay); // plays the entire say
response.Append(mygather); // only after playing entire say am I able to gather

/* I seem to able to do only the following with limited markup capability */
response.Append(mygather.Say("Here is something I want to say but have little ability to fine tune the say with .Emphasis .Break or .Prosody controls"));

So, is it possible to just mark up my Say with all the controls I want inside a gather (much like the top code block above), save that to an XML file, and then point the response object to that XML file, and still be able to capture the users voice or digit response in my C# app?

  • The `Gather` class has a [`Say`](https://www.twilio.com/docs/libraries/reference/twilio-csharp/5.13.5/class_twilio_1_1_twi_m_l_1_1_voice_1_1_gather.html#aad89b770f43b34f1e64d20362f72b2c2) method that is probably what you want. – Ackdari Nov 11 '20 at 18:41
  • `Gather` also has an `Append` method to add arbitrary TwiML elements as children. Seems like you could call `mygather.Append(mysay)` to achieve what you want, but I've never worked with Twilio and have no access to test. https://www.twilio.com/docs/libraries/reference/twilio-csharp/5.13.5/class_twilio_1_1_twi_m_l_1_1_voice_1_1_gather.html#a30ad7b665e061150c31ef7cc28a51342 – tychon Nov 11 '20 at 18:46
  • Ackdari - Yes the Gather class does have a Say method as I noted. The issue is that it has very few methods to shape the Say like the Say verb object you'd think it was based upon. – Curtis Jones Nov 12 '20 at 00:28
  • tychon - I will look into that method for gather and see if it works. – Curtis Jones Nov 12 '20 at 00:29
  • tychon - thanks, the Append method on the gather seems to work! – Curtis Jones Nov 12 '20 at 02:17
  • One last comment for posterity. The gather "worked" in that it did include the say markup emphasis and other tags. However, it would not honor the emphasis tag -- and in fact -- would not say anything that had an emphasis tag in it. Through trial and error, it turned out that any -neural "polly" voice does not like the emphasis tag (and probably other voice-shaping tags). If you switch to a non-neural voice it works as expected. – Curtis Jones Nov 12 '20 at 12:58
  • The `Say` method take a `Say` object. so it is like the `Append` method only specialized for the `Say` tag. So you could just do `myGather.Say(mySay)` – Ackdari Nov 12 '20 at 18:28

1 Answers1

1

Decided to post the answer for posterity, in case anyone else has a similar issue and happens upon this page.

The proper way to include a say object within a gather object is:

/* include the marked up mysay object within the mygather object */
mygather.Append(mysay); 

/* speak the marked up mysay twiML while waiting an answer */
response.Append(mygather); 

The other caveat is that if the mysay has specified a -Neural voice, it will not play some of the marked up tags like .Emphasis.

The following table shows the compatibility for the marked up tags: https://docs.aws.amazon.com/polly/latest/dg/supportedtags.html

Thanks to user "tychon" (above in comments under question) who supplied the hint to help me find the answer.