📄 promptmanager.cpp
字号:
// (3) audio
case NODE_AUDIO:
{
// (3.1) Process the 'expr' if provided. NOTE: Exactly one of 'src' and
// 'expr' MUST be specified.
vxistring expr;
if (elem.GetAttribute(ATTRIBUTE_EXPR, expr)) {
// (3.1.1) Handle the expr case.
VXIValue * value = translator.EvaluateExpression(expr);
if (value == NULL) return; // Ignore this element
// (3.1.2) Handle audio content from <record> elements.
if (VXIValueGetType(value) == VALUE_CONTENT) {
AddContent(props, sofar, value);
return;
}
// (3.1.3) Otherwise, try to convert the type into a string.
bool conversionFailed = !ConvertValueToString(value, expr);
VXIValueDestroy(&value);
if (conversionFailed) {
log->LogDiagnostic(0, L"PromptManager::ProcessSegments - "
L"audio src evaluation failed");
throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC,
L"audio src evaluation failed");
}
if (expr.empty()) return; // Ignore this element
}
// (3.2) Add an <audio> element to the current request.
sofar += L"<audio";
AddSSMLAttribute(elem, ATTRIBUTE_SRC, expr.c_str(), L"src", sofar);
AddSSMLAttribute(elem, ATTRIBUTE_FETCHTIMEOUT,
propertyList.GetProperty(L"fetchtimeout"),
L"fetchtimeout", sofar);
AddSSMLAttribute(elem, ATTRIBUTE_FETCHHINT,
propertyList.GetProperty(L"audiofetchhint"),
L"fetchhint", sofar);
AddSSMLAttribute(elem, ATTRIBUTE_MAXAGE,
propertyList.GetProperty(L"audiomaxage"),
L"maxage", sofar);
AddSSMLAttribute(elem, ATTRIBUTE_MAXSTALE,
propertyList.GetProperty(L"audiomaxstale"),
L"maxstale", sofar);
// Add in the alternate text (if any).
if (elem.hasChildren()) {
sofar += L">";
for (VXMLNodeIterator it(elem); it; ++it)
ProcessSegments(*it, item, propertyList, translator,
bargein, props, sofar);
sofar += L"</audio>";
}
else
sofar += L"/>";
return;
}
// (4) <value>
case NODE_VALUE:
{
// (4.1) Evaluate the expression. Can we handle this type?
vxistring expr;
if (!elem.GetAttribute(ATTRIBUTE_EXPR, expr) || expr.empty()) return;
VXIValue * value = translator.EvaluateExpression(expr);
if (value == NULL) return;
// (4.2) Convert to a string a play as TTS.
bool conversionFailed = !ConvertValueToString(value, expr);
VXIValueDestroy(&value);
if (conversionFailed) {
log->LogDiagnostic(0, L"PromptManager::ProcessSegments - "
L"value expr was not a simple type");
throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC,
L"value expr gave invalid type");
}
if (expr.empty()) return;
AppendTextSegment(sofar, expr);
return;
}
break;
// (5) <enumerate>
case NODE_ENUMERATE:
{
// (5.1) Is enumerate valid in this location?
if (item == 0)
throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC, L"invalid use "
L"of enumerate element");
bool foundMatch = false;
for (VXMLNodeIterator it(item); it; ++it) {
// (5.2) Ignore anything which isn't an <option> or <choice> grammar.
if ((*it).GetType() != VXMLNode::Type_VXMLElement) continue;
const VXMLNode & tmp = *it;
const VXMLElement & itemElem = reinterpret_cast<const VXMLElement&>(tmp);
switch (itemElem.GetName()) {
case NODE_CHOICE:
case NODE_OPTION:
foundMatch = true;
break;
default:
continue;
}
// (5.3) Convert item into text.
vxistring promptText;
for (VXMLNodeIterator choiceNode(itemElem); choiceNode; ++choiceNode) {
if ((*choiceNode).GetType() == VXMLNode::Type_VXMLContent) {
if (!promptText.empty()) promptText += SPACE;
const VXMLNode temp = *choiceNode;
promptText += reinterpret_cast<const VXMLContent &>(temp).GetValue();
/*
// Get text from this node.
vxistring text = reinterpret_cast<const VXMLContent &>
(*choiceNode).GetValue();
if (!promptText.empty()) promptText += SPACE;
// Strip the leading whitespace.
while (text.length() > 0) {
VXIchar c = text[0];
if (c == ' ' || c == '\r' || c == '\n' || c == '\t')
text.erase(0, 1);
else {
promptText += text;
break;
}
}
// Strip off any trailing whitespace
while (promptText.length() > 0) {
unsigned int len = promptText.length();
VXIchar c = promptText[len - 1];
if (c == ' ' || c == '\r' || c == '\n' || c == '\t')
promptText.erase(len - 1, 1);
else break;
}
*/
}
}
// (5.4) Handle the simple case where enumerate does not specify a
// format string.
if (!elem.hasChildren()) {
AppendTextSegment(sofar, promptText);
sofar += L"<break time='small'/>";
}
else {
// (5.5) Get the associated dtmf value.
vxistring dtmfText;
itemElem.GetAttribute(ATTRIBUTE_DTMF, dtmfText);
translator.SetVariable(L"_prompt", promptText);
translator.SetVariable(L"_dtmf", dtmfText);
for (VXMLNodeIterator subNode(elem); subNode; ++subNode)
ProcessSegments(*subNode, item, propertyList, translator,
bargein, props, sofar);
}
}
// (5.6) Final check - was there an <option> or <choice>?
if (!foundMatch)
throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC, L"invalid use "
L"of enumerate element");
break;
}
default:
log->LogError(999, SimpleLogger::MESSAGE,
L"logic error PromptManager::ProcessSegments");
throw VXIException::Fatal();
}
}
void PromptManager::AddContent(VXIMapHolder & props,
vxistring & sofar,
VXIValue * value)
{
VXIMapHolder allRefs(NULL);
// (1) Get existing map (if it exists) or create a new one.
const VXIValue * temp = VXIMapGetProperty(props.GetValue(),
PROMPT_AUDIO_REFS);
if (temp != NULL && VXIValueGetType(temp) == VALUE_MAP)
allRefs.Acquire(VXIMapClone(reinterpret_cast<const VXIMap *>(temp)));
else
allRefs.Acquire(VXIMapCreate());
if (allRefs.GetValue() == NULL) throw VXIException::OutOfMemory();
// (2) Generate a hidden name.
vxistring hiddenName;
VXMLDocumentModel::CreateHiddenVariable(hiddenName);
hiddenName.erase(0, 1);
hiddenName = vxistring(PROMPT_AUDIO_REFS_SCHEME) + hiddenName;
// (3) Place hidden name and content into the map.
VXIMapSetProperty(allRefs.GetValue(), hiddenName.c_str(), value);
// (4) Replace the references map with the updated one.
VXIMapSetProperty(props.GetValue(), PROMPT_AUDIO_REFS,
reinterpret_cast<VXIValue *>(allRefs.Release()));
// (5) Handle the SSML case
sofar += L"<mark name=\"";
sofar += hiddenName;
sofar += L"\"/>";
}
bool PromptManager::ProcessPrefetchPrompts(const VXMLNode & node, const VXMLElement& item,
const PropertyList & propertyList,
PromptTranslator & translator,
vxistring & sofar)
{
bool rc = false;
switch (node.GetType()) {
case VXMLNode::Type_VXMLContent:
{
const VXMLContent & content = reinterpret_cast<const VXMLContent &>(node);
sofar += content.GetValue();
return true;
}
case VXMLNode::Type_VXMLElement:
break;
default:
return false;
}
// Look at other type
const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(node);
switch (elem.GetName())
{
// audio
case NODE_AUDIO:
{
// ignore this entire prompt if expr is found
vxistring expr;
if (elem.GetAttribute(ATTRIBUTE_EXPR, expr) == true)
return false;
else {
rc = true;
sofar += L"<audio";
AddSSMLAttribute(elem, ATTRIBUTE_SRC, expr.c_str(), L"src", sofar);
AddSSMLAttribute(elem, ATTRIBUTE_FETCHTIMEOUT,
propertyList.GetProperty(L"fetchtimeout"),
L"fetchtimeout", sofar);
AddSSMLAttribute(elem, ATTRIBUTE_FETCHHINT,
propertyList.GetProperty(L"audiofetchhint"),
L"fetchhint", sofar);
AddSSMLAttribute(elem, ATTRIBUTE_MAXAGE,
propertyList.GetProperty(L"audiomaxage"),
L"maxage", sofar);
AddSSMLAttribute(elem, ATTRIBUTE_MAXSTALE,
propertyList.GetProperty(L"audiomaxstale"),
L"maxstale", sofar);
// Add in the alternate text (if any).
if (elem.hasChildren()) {
sofar += L">";
for (VXMLNodeIterator it(elem); rc && it; ++it)
rc = ProcessPrefetchPrompts(*it, item, propertyList, translator, sofar);
sofar += L"</audio>";
}
else
sofar += L"/>";
if( rc ) sofar += L"</speak>";
}
} break;
// value tag and other tags found inside a prompt, do not fetch this entire prompt
// case NODE_VALUE: case NODE_ENUMERATE:
default:
return false;
}
return rc;
}
void PromptManager::PreloadPrompts(const VXMLElement& doc,
PropertyList & properties,
PromptTranslator & translator)
{
VXIMapHolder temp(NULL);
DoPreloadPrompts(doc, properties, temp, translator);
}
void PromptManager::DoPreloadPrompts(const VXMLElement& doc,
PropertyList & properties,
VXIMapHolder & levelProperties,
PromptTranslator & translator)
{
// (1) Look for prompts in current nodes.
for (VXMLNodeIterator it(doc); it; ++it) {
VXMLNode child = *it;
if (child.GetType() != VXMLNode::Type_VXMLElement) continue;
const VXMLElement & element = reinterpret_cast<const VXMLElement &>(child);
VXMLElementType elementName = element.GetName();
// (2) Handle anything which is not a prompt.
if (elementName != NODE_PROMPT) {
bool doPop = properties.PushProperties(element);
if (doPop) {
VXIMapHolder temp(NULL);
DoPreloadPrompts(element, properties, temp, translator);
}
else
DoPreloadPrompts(element, properties, levelProperties, translator);
if (doPop) properties.PopProperties();
continue;
}
// (3) Handle <prompt>.
// (3.1) Ignore anything other than simple content.
if (!element.hasChildren()) continue;
// (3.2) Find the fetchhint setting.
if (levelProperties.GetValue() == NULL) {
levelProperties.Acquire(VXIMapCreate());
properties.GetProperties(levelProperties);
}
vxistring attr = L"";
if (element.GetAttribute(ATTRIBUTE_FETCHHINT, attr) != true) {
const VXIValue * v = VXIMapGetProperty(levelProperties.GetValue(),
L"audiofetchhint");
if (VXIValueGetType(v) == VALUE_STRING)
attr = VXIStringCStr(reinterpret_cast<const VXIString *>(v));
}
// (3.3) Get the level properties if necessary & add the prefetch setting.
if (attr == L"prefetch")
AddParamValue(levelProperties, PROMPT_PREFETCH_REQUEST, 1);
else
AddParamValue(levelProperties, PROMPT_PREFETCH_REQUEST, 0);
// (3.4) Create full ssml document
vxistring ssmldoc;
bool shouldPrefetch = true;
for (VXMLNodeIterator it2(element); shouldPrefetch && it2; ++it2)
shouldPrefetch = ProcessPrefetchPrompts(*it2, element, properties, translator, ssmldoc);
// (3.5) Call prefetch for prompt.
if( shouldPrefetch ) {
prompt->Prefetch(prompt, VXI_MIME_SSML, NULL,
ssmldoc.c_str(),
levelProperties.GetValue());
}
// (3.6) We might undo the addition of PROMPT_PREFETCH_REQUEST, but this
// parameter is always set and will be overwritten on the next pass.
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -