📄 promptmanager.cpp
字号:
/****************License************************************************ * * Copyright 2000-2001. SpeechWorks International, Inc. * * Use of this software is subject to notices and obligations set forth * in the SpeechWorks Public License - Software Version 1.1 which is * included with this software. * * SpeechWorks is a registered trademark, and SpeechWorks Here, * DialogModules and the SpeechWorks logo are trademarks of SpeechWorks * International, Inc. in the United States and other countries. * ***********************************************************************/#include "PromptManager.hpp"#include "SimpleLogger.hpp" // for SimpleLogger#include "VXIprompt.h" // for VXIpromptInterface#include "VXML.h" // for node names#include "DocumentModel.hpp" // for VXMLNode, VXMLElement#include "CommonExceptions.hpp" // for InterpreterEvent, OutOfMemory#include "PropertyList.hpp" // for PropertyList#include <sstream>VXIchar SPACE = ' ';//#############################################################################bool static ConvertValueToString(const VXIValue * value, vxistring & source){ if (value == NULL) return false; switch (VXIValueGetType(value)) { case VALUE_INTEGER: { std::basic_stringstream<VXIchar> attrStream; attrStream << VXIIntegerValue(reinterpret_cast<const VXIInteger *>(value)); source = attrStream.str(); return true; } case VALUE_FLOAT: { std::basic_stringstream<VXIchar> attrStream; attrStream << VXIFloatValue(reinterpret_cast<const VXIFloat *>(value)); source = attrStream.str(); return true; } case VALUE_STRING: source = VXIStringCStr(reinterpret_cast<const VXIString *>(value)); return true; case VALUE_VECTOR: case VALUE_MAP: case VALUE_PTR: case VALUE_CONTENT: default: return false; }}inline void AddSSMLAttribute(const VXMLElement & elem, VXMLAttributeType attr, const VXIchar * const name, vxistring & sofar){ vxistring attrString; if (!elem.GetAttribute(attr, attrString)) return; sofar += SPACE; sofar += name; sofar += L"=\""; // We need to escape three characters: (",<,&) -> (", <, &) vxistring::size_type pos = 0; while ((pos = attrString.find_first_of(L"\"<&", pos)) != vxistring::npos) { switch (attrString[pos]) { case '\"': attrString.replace(pos, 1, L"""); ++pos; break; case '<': attrString.replace(pos, 1, L"<"); ++pos; break; case '&': attrString.replace(pos, 1, L"&"); ++pos; break; } }; sofar += attrString; sofar += L"\"";}inline void AppendTextSegment(vxistring & sofar, const vxistring & addition, bool isSSML){ if (addition.empty()) return; vxistring::size_type pos = sofar.length(); if (!sofar.empty()) sofar += SPACE; sofar += addition; if (isSSML) { // We need to escape two characters: (<,&) -> (<, &) while ((pos = sofar.find_first_of(L"<&", pos)) != vxistring::npos) { switch (sofar[pos]) { case '<': sofar.replace(pos, 1, L"<"); ++pos; break; case '&': sofar.replace(pos, 1, L"&"); ++pos; break; } } }}inline void ConvertToXML(vxistring & sofar, bool & isSSML){ if (isSSML) return; vxistring temp; AppendTextSegment(temp, sofar, true); sofar = temp; isSSML = true;}//#############################################################################////////// About prompts://// Prompts may be defined in two places within VXML documents.// 1) form items - menu, field, initial, record, transfer, subdialog, object// 2) executable content - block, catch, filled//// The <enumerate> element only is valid with parent menu or fields having one// or more option elements. Otherwise an error.semantic results.//// From the VXML working drafts, barge-in may be controlled on a prompt by// prompt basis. There are several unresolved issues with this request.// Instead this implements a different tactic.bool PromptManager::ConnectResources(SimpleLogger * l, VXIpromptInterface * p){ if (l == NULL || p == NULL) return false; log = l; prompt = p; enabledSegmentInQueue = false; timeout = -1; return true;}void PromptManager::PlayFiller(const vxistring & src){ log->LogDiagnostic(2, L"PromptManager::PlayFiller()"); if (src.empty()) return; prompt->PlayFiller(prompt, NULL, src.c_str(), NULL, NULL, 0);}void PromptManager::Play(){ log->LogDiagnostic(2, L"PromptManager::Play()"); VXIpromptResult temp; prompt->Wait(prompt, &temp); prompt->Play(prompt); enabledSegmentInQueue = false; timeout = -1;}void PromptManager::PlayAll(){ log->LogDiagnostic(2, L"PromptManager::PlayAll()"); VXIpromptResult temp; prompt->Play(prompt); prompt->Wait(prompt, &temp); enabledSegmentInQueue = false; timeout = -1;}int PromptManager::GetMillisecondTimeout() const{ return timeout;}void PromptManager::Queue(const VXMLNode & node, const VXMLElement & ref, const PropertyList & propertyList, PromptTranslator & translator){ log->LogDiagnostic(2, L"PromptManager::Queue()"); // (1) Find <field> or <menu> associated with this prompt, if any. This is // used by the <enumerate> element. VXMLElement item = ref; while (item != 0) { VXMLElementType type = item.GetName(); if (type == NODE_FIELD || type == NODE_MENU) break; item = item.GetParent(); } // (2) Get properties. VXIMapHolder properties; if (properties.GetValue() == NULL) throw VXIException::OutOfMemory(); // (2.1) Flatten the property list. propertyList.GetProperties(properties); // (2.2) Add the URI information. propertyList.GetFetchobjBase(properties); // (3) Handle <prompt> elements vxistring language; vxistring sofar; bool isSSML = false; PromptManager::BargeIn bargein = PromptManager::ENABLED; const VXIchar * j = propertyList.GetProperty(PROP_BARGEIN); if (j != NULL && vxistring(L"false") == j) bargein = PromptManager::DISABLED; if (node.GetType() == VXMLNode::Type_VXMLElement && reinterpret_cast<const VXMLElement &>(node).GetName() == NODE_PROMPT) { const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(node); // (3.1) Update timeout if specified. vxistring timeoutString; if (elem.GetAttribute(ATTRIBUTE_TIMEOUT, timeoutString) == true) PropertyList::ConvertTimeToMilliseconds(*log, timeoutString, timeout); // (3.2) Get bargein setting. vxistring bargeinAttr; if (elem.GetAttribute(ATTRIBUTE_BARGEIN, bargeinAttr) == true) { bargein = PromptManager::ENABLED; if (bargeinAttr == L"false") bargein = PromptManager::DISABLED; } // (3.3) Update language. if (elem.GetAttribute(ATTRIBUTE_XMLLANG, language) == true) AddParamValue(properties, PROMPT_LANGUAGE, language); // (3.4) Recursively handle contents of the prompt. for (VXMLNodeIterator it(elem); it; ++it) ProcessSegments(*it, item, propertyList, translator, bargein, properties, sofar, isSSML); } // (4) Otherwise, this is simple content or an audio / tts element. else ProcessSegments(node, item, propertyList, translator, bargein, properties, sofar, isSSML); // (5) Add a new segment. if (!sofar.empty()) { if (!isSSML) AddSegment(SEGMENT_TEXT, sofar, properties, bargein); else { // Retrieve language from properties, if not specified on <prompt> if (language.empty()) { const VXIchar * j = propertyList.GetProperty(PropertyList::Language); if (j != NULL) { language = j; AddParamValue(properties, PROMPT_LANGUAGE, j); } } vxistring prompt(L"<?xml version='1.0'?>"); if (!language.empty()) { prompt += L"<speak xml:lang='"; prompt += language; prompt += L"'>"; } else prompt += L"<speak>"; prompt += sofar; prompt += L"</speak>"; AddSegment(SEGMENT_SSML, prompt, properties, bargein); } }}void PromptManager::Queue(const vxistring & uri){ if (uri.empty()) return; AddSegment(PromptManager::SEGMENT_AUDIO, uri, VXIMapHolder(), PromptManager::UNSPECIFIED);}bool PromptManager::AddSegment(PromptManager::SegmentType type, const vxistring & data, const VXIMapHolder & properties, PromptManager::BargeIn bargein, bool throwExceptions){ const VXIMap * propMap = properties.GetValue(); VXIpromptResult result; // Handle the easy case. switch (type) { case PromptManager::SEGMENT_AUDIO: result = prompt->Queue(prompt, NULL, data.c_str(), NULL, propMap); break; case PromptManager::SEGMENT_SSML: result = prompt->Queue(prompt, VXI_MIME_SSML, NULL, data.c_str(), propMap); break; case PromptManager::SEGMENT_TEXT: result = prompt->Queue(prompt, VXI_MIME_UNICODE_TEXT, NULL, data.c_str(), propMap); break; } if (throwExceptions) { switch (result) { case VXIprompt_RESULT_SUCCESS: break; case VXIprompt_RESULT_TTS_BAD_LANGUAGE: throw VXIException::InterpreterEvent(EV_UNSUPPORT_LANGUAGE); case VXIprompt_RESULT_FETCH_TIMEOUT: case VXIprompt_RESULT_FETCH_ERROR: case VXIprompt_RESULT_NON_FATAL_ERROR: throw VXIException::InterpreterEvent(EV_ERROR_BADFETCH); case VXIprompt_RESULT_HW_BAD_TYPE: throw VXIException::InterpreterEvent(EV_UNSUPPORT_FORMAT); case VXIprompt_RESULT_BAD_SAYAS_CLASS: case VXIprompt_RESULT_TTS_ACCESS_ERROR: case VXIprompt_RESULT_TTS_BAD_DOCUMENT: case VXIprompt_RESULT_TTS_SYNTAX_ERROR: case VXIprompt_RESULT_TTS_ERROR: default: throw VXIException::InterpreterEvent(EV_ERROR_SEMANTIC); } } switch (bargein) { case PromptManager::DISABLED: if (!enabledSegmentInQueue) prompt->Play(prompt); break; case PromptManager::ENABLED: enabledSegmentInQueue = true; break; case PromptManager::UNSPECIFIED: break; } return result == VXIprompt_RESULT_SUCCESS;}void PromptManager::ProcessSegments(const VXMLNode & node, const VXMLElement & item, const PropertyList & propertyList, PromptTranslator & translator, PromptManager::BargeIn bargein, VXIMapHolder & props, vxistring & sofar, bool & isSSML){ // (1) Handle bare content. switch (node.GetType()) { case VXMLNode::Type_VXMLContent: { const VXMLContent & content = reinterpret_cast<const VXMLContent &>(node); AppendTextSegment(sofar, content.GetValue(), isSSML); return; } case VXMLNode::Type_VXMLElement: break; default: // This should never happen. log->LogError(999, SimpleLogger::MESSAGE, L"unexpected type in PromptManager::ProcessSegments"); throw VXIException::Fatal(); } // (2) Retrieve fetch properties (if we haven't already) const VXMLElement & elem = reinterpret_cast<const VXMLElement &>(node); vxistring attr; switch (elem.GetName()) { // (3) audio case NODE_AUDIO: { // (3.1) Determine the source of the audio. vxistring source; // (3.1.1) src has priority over expr. elem.GetAttribute(ATTRIBUTE_SRC, source); if (source.empty()) { elem.GetAttribute(ATTRIBUTE_EXPR, source); VXIValue * value = translator.EvaluateExpression(source); if (value != NULL) { // (3.1.2) Handle audio content from <record> elements. if (VXIValueGetType(value) == VALUE_CONTENT) { AddContent(elem, item, propertyList, translator, bargein, props, sofar, value, isSSML); return; } // (3.1.3) Otherwise, try to convert the type into a string. bool conversionFailed = !ConvertValueToString(value, source); 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"); } } } // (3.1.4) Empty audio elements should be ignored. if (source.empty()) return; // (3.2) Get fetch properties. // (3.2.1) Create new audio reference data map. VXIMapHolder audioData;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -