📄 promptmanager.cpp
字号:
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. } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -