📄 promptmanager.cpp
字号:
if (audioData.GetValue() == NULL) throw VXIException::OutOfMemory(); // (3.2.2) Populate the inner map. AddParamValue(audioData, PROMPT_AUDIO_REF_SRC, source); propertyList.GetFetchobjCacheAttrs(elem, PropertyList::Grammar, audioData); // (3.2.3) Generate a hidden name and place the inner map inside the // properties. vxistring hiddenName; VXMLDocumentModel::CreateHiddenVariable(hiddenName); VXIMapHolder allRefs(NULL); // 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(); // Place references for this value into the 'all refs' map. VXIMapSetProperty(allRefs.GetValue(), hiddenName.c_str(), reinterpret_cast<VXIValue *>(audioData.Release())); // And replace the 'all refs' map in the properties. VXIMapSetProperty(props.GetValue(), PROMPT_AUDIO_REFS, reinterpret_cast<VXIValue *>(allRefs.Release())); // (3.2.4) Create fake 'src' for this audio element. hiddenName = vxistring(PROMPT_AUDIO_REFS_SCHEME) + hiddenName; // (3.3) For SSML, simply add a new audio element. if (isSSML) { sofar += L"<audio src=\""; // We need to escape three characters: (",<,&) -> (", <, &) vxistring::size_type pos = 0; while ((pos = hiddenName.find_first_of(L"\"<&", pos)) != vxistring::npos) { switch (hiddenName[pos]) { case '\"': hiddenName.replace(pos, 1, L"""); ++pos; break; case '<': hiddenName.replace(pos, 1, L"<"); ++pos; break; case '&': hiddenName.replace(pos, 1, L"&"); ++pos; break; } }; sofar += hiddenName; sofar += L"\""; // Deal with alternate text. if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</audio>"; } else sofar += L"/>"; return; } // (3.4) Handle simple data case. // (3.4.1) First add any existing text. if (!sofar.empty()) { AddSegment(SEGMENT_TEXT, sofar, props, bargein); sofar.erase(); } // (3.4.2) Then add the audio segment. if (!AddSegment(SEGMENT_AUDIO, hiddenName, props, bargein, !elem.hasChildren())) { // Unable to queue audio segment. Resort to backup. for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); } return; } // (4) Handle SSML tags. case NODE_BREAK: ConvertToXML(sofar, isSSML); sofar += L"<break"; AddSSMLAttribute(elem, ATTRIBUTE_SIZE, L"size", sofar); AddSSMLAttribute(elem, ATTRIBUTE_TIME, L"time", sofar); sofar += L"/>"; return; case NODE_EMPHASIS: ConvertToXML(sofar, isSSML); sofar += L"<emphasis"; AddSSMLAttribute(elem, ATTRIBUTE_LEVEL, L"level", sofar); if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</emphasis>"; } else sofar += L"/>"; return; case NODE_MARK: ConvertToXML(sofar, isSSML); sofar += L"<mark"; AddSSMLAttribute(elem, ATTRIBUTE_NAME, L"name", sofar); sofar += L"/>"; return; case NODE_PARAGRAPH: ConvertToXML(sofar, isSSML); sofar += L"<p"; AddSSMLAttribute(elem, ATTRIBUTE_XMLLANG, L"xml:lang", sofar); if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</p>"; } else sofar += L"/>"; return; case NODE_PHONEME: ConvertToXML(sofar, isSSML); sofar += L"<phoneme"; AddSSMLAttribute(elem, ATTRIBUTE_PH, L"ph", sofar); AddSSMLAttribute(elem, ATTRIBUTE_ALPHABET, L"alphabet", sofar); if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</phoneme>"; } else sofar += L"/>"; return; case NODE_PROSODY: ConvertToXML(sofar, isSSML); sofar += L"<prosody"; AddSSMLAttribute(elem, ATTRIBUTE_PITCH, L"pitch", sofar); AddSSMLAttribute(elem, ATTRIBUTE_CONTOUR, L"contour", sofar); AddSSMLAttribute(elem, ATTRIBUTE_RANGE, L"range", sofar); AddSSMLAttribute(elem, ATTRIBUTE_RATE, L"rate", sofar); AddSSMLAttribute(elem, ATTRIBUTE_DURATION, L"duration", sofar); AddSSMLAttribute(elem, ATTRIBUTE_VOLUME, L"volume", sofar); if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</prosody>"; } else sofar += L"/>"; return; case NODE_SAYAS: ConvertToXML(sofar, isSSML); sofar += L"<say-as"; AddSSMLAttribute(elem, ATTRIBUTE_TYPE, L"type", sofar); AddSSMLAttribute(elem, ATTRIBUTE_SUB, L"sub", sofar); if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</say-as>"; } else sofar += L"/>"; return; case NODE_SENTENCE: ConvertToXML(sofar, isSSML); sofar += L"<s"; AddSSMLAttribute(elem, ATTRIBUTE_XMLLANG, L"xml:lang", sofar); if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</s>"; } else sofar += L"/>"; return; case NODE_VOICE: ConvertToXML(sofar, isSSML); sofar += L"<voice"; AddSSMLAttribute(elem, ATTRIBUTE_GENDER, L"gender", sofar); AddSSMLAttribute(elem, ATTRIBUTE_AGE, L"age", sofar); AddSSMLAttribute(elem, ATTRIBUTE_CATEGORY, L"category", sofar); AddSSMLAttribute(elem, ATTRIBUTE_VARIANT, L"variant", sofar); AddSSMLAttribute(elem, ATTRIBUTE_NAME, L"name", sofar); if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</voice>"; } else sofar += L"/>"; return; // (5) <value> case NODE_VALUE: { // (5.1) Evaluate the expression. Can we handle this type? vxistring expr; if (elem.GetAttribute(ATTRIBUTE_EXPR, expr) == false || expr.empty()) return; VXIValue * value = translator.EvaluateExpression(expr); if (value == NULL) return; VXIvalueType valueType = VXIValueGetType(value); switch (valueType) { case VALUE_INTEGER: case VALUE_FLOAT: case VALUE_STRING: case VALUE_CONTENT: break; case VALUE_VECTOR: case VALUE_MAP: case VALUE_PTR: default: VXIValueDestroy(&value); 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"); } // (5.2) Handle VXIContent. if (valueType == VALUE_CONTENT) { AddContent(elem, item, propertyList, translator, bargein, props, sofar, value, isSSML); return; } // (5.3) OTHERWISE this should be played as TTS. Convert value to string. ConvertValueToString(value, expr); VXIValueDestroy(&value); vxistring type; elem.GetAttribute(ATTRIBUTE_TYPE, type); // (5.3.1) Is this simple text? vxistring::size_type pos = expr.find('<'); if (type.empty() && (pos == vxistring::npos || expr.find('>', pos) == vxistring::npos)) { AppendTextSegment(sofar, expr, isSSML); return; } // (5.3.2) Otherwise.... ConvertToXML(sofar, isSSML); if (!type.empty()) { sofar += L"<say-as type=\""; sofar += type; sofar += L"\">"; } sofar += expr; if (!type.empty()) { sofar += L"</say-as>"; } return; } // (3.4) <enumerate> case NODE_ENUMERATE: { // (3.4.1) Is enumerate valid in this location? if (item == 0) throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC, L"invalid use " L"of enumerate element"); for (VXMLNodeIterator it(item); it; ++it) { // (3.4.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: break; default: continue; } // (3.4.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 & tmp = *choiceNode; promptText += reinterpret_cast<const VXMLContent &>(tmp).GetValue(); } } // (3.4.4) Handle the simple case where enumerate does not specify a // format string. if (!elem.hasChildren()) { ConvertToXML(sofar, isSSML); AppendTextSegment(sofar, promptText, isSSML); sofar += L"<break size='small'/>"; } else { // (3.4.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, isSSML); } } break; } default: log->LogError(999, SimpleLogger::MESSAGE, L"logic error PromptManager::ProcessSegments"); throw VXIException::Fatal(); }}void PromptManager::AddContent(const VXMLElement & elem, const VXMLElement & item, const PropertyList & propertyList, PromptTranslator & translator, BargeIn bargein, VXIMapHolder & props, vxistring & sofar, VXIValue * value, bool & isSSML){ // (1) Create new audio reference data map. VXIMapHolder valueData; if (valueData.GetValue() == NULL) throw VXIException::OutOfMemory(); // (2) Populate the inner map. VXIMapSetProperty(valueData.GetValue(), PROMPT_AUDIO_REF_DATA, value); propertyList.GetFetchobjCacheAttrs(elem, PropertyList::Grammar, valueData); // (3) Generate a hidden name and place the inner map inside the properties. vxistring hiddenName; VXMLDocumentModel::CreateHiddenVariable(hiddenName); VXIMapHolder allRefs(NULL); // 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(); // Place references for this value into the 'all refs' map. VXIMapSetProperty(allRefs.GetValue(), hiddenName.c_str(), reinterpret_cast<VXIValue *>(valueData.Release())); // And replace the 'all refs' map in the properties. VXIMapSetProperty(props.GetValue(), PROMPT_AUDIO_REFS, reinterpret_cast<VXIValue *>(allRefs.Release())); // (5.2.4) Create fake 'src' for this audio element. hiddenName = vxistring(PROMPT_AUDIO_REFS_SCHEME) + hiddenName; // (5.2.5) Handle the SSML case if (isSSML) { sofar += L"<audio src=\""; sofar += hiddenName; sofar += L"\""; if (elem.hasChildren()) { sofar += L">"; for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, props, sofar, isSSML); sofar += L"</audio>"; } else sofar += L"/>"; return; } // (5.2.6) Otherwise, we're dealing simple text & audio. if (!sofar.empty()) { AddSegment(SEGMENT_TEXT, sofar, props, bargein); sofar.erase(); } AddSegment(SEGMENT_AUDIO, hiddenName, props, bargein); return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -