My VoiceXML provider, Nexmo, seems not to handle the xml:lang="es-ES" attribute in the root vxml (This is generated by Rivr with a context.setLanguage("es-ES") in my Dialog)
I want Nexmo to use a spanish TTS engine but as I am using Rivr, I can't see where I can specify that I want the "prompt" to include, for example, xml:lang="es-es-female", so it generates VoiceXML:
<prompt xml:lang="es-es-female">
Hola.
</prompt>
interaction().addPrompt() only accepts the SpeechSynthesis object which does not allow (as far as I see) language options.
I've also tried include SSML in the SpeechSynthesis object (using a DocumentFragment as I see in Rivr Javadoc) but that won't work. Probably Nexmo does not support SSML.
Any workarounds? (A part from changing to a better VoiceXML provider)
Thanks a lot!!!
If you only want to play a message without getting input from the user, use can use the Message class:
//Play a synthesis message in another language
Message message = new Message("synthesis-french-message",
new SpeechSynthesis("Ceci est un message."));
message.setLanguage("fr-CA");
DialogueUtils.doTurn(message, context);
If you need to specify the language for a prompt in an Interaction, this can be done with the InteractionBuilder. The setLanguage() method can be used before the addPrompt() method. Multiple languages can be used within the same interaction:
Interaction interaction = OutputTurns.interaction("multilingual-interaction")
.setLanguage("es-ES")
.addPrompt(new SpeechSynthesis("Holá."))
.setLanguage("fr-CA")
.addPrompt(new SpeechSynthesis("Bonjour."))
.build(new SpeechRecognition(new GrammarReference("grammar.grxml")),
Duration.seconds(2));
DialogueUtils.doTurn(interaction, context);
If you don't want to use the builder, you can do it by hand but it's much longer:
List<Interaction.Prompt> prompts = new ArrayList<Interaction.Prompt>();
Interaction.Prompt spanishPrompt = new Interaction.Prompt(new SpeechSynthesis("Holá."));
spanishPrompt.setLanguage("es-ES");
prompts.add(spanishPrompt);
Interaction.Prompt frenchPrompt = new Interaction.Prompt(new SpeechSynthesis("Bonjour."));
frenchPrompt.setLanguage("fr-CA");
prompts.add(frenchPrompt);
SpeechRecognition speechRecognition = new SpeechRecognition(new GrammarReference("grammar.grxml"));
FinalRecognitionWindow finalRecognitionWindow = new FinalRecognitionWindow(speechRecognition,
Duration.seconds(2));
Interaction interaction2 = new Interaction("multilingual-interaction2",
prompts,
finalRecognitionWindow);
DialogueUtils.doTurn(interaction2, context);
The output VoiceXML is:
<?xml version="1.0" encoding="UTF-8"?>
<vxml application="/rivr-cookbook-message-language/dialogue/root/efe10575-1766-48fb-9e13-572a771bc5f4" version="2.1"
xmlns="http://www.w3.org/2001/vxml">
<script>application.rivr.localErrorHandling = false; application.rivr.inputTurn = {};</script>
<form id="form">
<block name="prompt0">
<prompt bargein="false" xml:lang="es-ES">Holá.</prompt>
</block>
<block name="prompt1">
<prompt bargein="false" xml:lang="fr-CA">Bonjour.</prompt>
</block>
<field name="recognition">
<grammar mode="voice" src="grammar.grxml" />
<property name="timeout" value="2000ms" />
</field>
<filled mode="any">
<script>application.rivr.addRecognitionResult()</script>
<goto next="#submitForm" />
</filled>
</form>
<catch>
<if cond="_event.substring(0, 5) == "error"">
<if cond="application.rivr.localErrorHandling">
<goto next="#fatalErrorForm" />
<else />
<script>application.rivr.localErrorHandling=true</script>
</if>
</if>
<script>application.rivr.addEventResult(_event, _message)</script>
<goto next="#submitForm" />
</catch>
<form id="fatalErrorForm">
<block>
<exit />
</block>
</form>
<form id="submitForm">
<block>
<var expr="application.rivr.toJson(application.rivr.inputTurn)" name="inputTurn" />
<if cond="application.rivr.hasRecording(application.rivr.inputTurn)">
<var expr="application.rivr.inputTurn.recordingMetaData.data" name="recording" />
<assign expr="undefined" name="application.rivr.inputTurn.recordingMetaData.data" />
<submit enctype="multipart/form-data" method="post" namelist="inputTurn recording"
next="/rivr-cookbook-message-language/dialogue/efe10575-1766-48fb-9e13-572a771bc5f4/0/multilingual-interaction2" />
<else />
<submit method="post" namelist="inputTurn"
next="/rivr-cookbook-message-language/dialogue/efe10575-1766-48fb-9e13-572a771bc5f4/0/multilingual-interaction2" />
</if>
</block>
</form>
</vxml>
Related
I am working with OWL and I have defined 2 classes and they share a data propertie:
<Declaration>
<DataProperty IRI="#hasLastName" />
</Declaration>
<DataPropertyDomain>
<DataProperty IRI="#hasLastName" />
<Class IRI="#Class1" />
</DataPropertyDomain>
<DataPropertyDomain>
<DataProperty IRI="#hasLastName" />
<Class IRI="#Class2" />
</DataPropertyDomain>
In java I have created a project that starting from an owl file and an xml file it creates a form.
in my xml file I define the sections of the form in this way:
<section>
<iri>http://www.sample.com/myontology#class1</iri>
<infoList>
<info type="text" property="http://www.sample.com/myontology#hasLastName" required="true" />
<info type="text" property="http://www.sample.com/myontology#hasFirstName" required="true" />
<info type="text" property="http://www.sample.com/myontology#hasEmail" required="false" />
<info type="text" property="http://www.sample.com/myontology#hasPhone" required="false" />
</infoList>
</section>
<section>
<iri>http://www.sample.com/myontology#class2</iri>
<infoList>
<info type="text" property="http://www.sample.com/myontology#hasLastName" required="true" />
<info type="text" property="http://www.sample.com/myontology#hasUser" required="false" />
<info type="text" property="http://www.sample.com/myontology#hasRole" required="false" />
</infoList>
</section>
How can I access the different Last name Properties for class 1 and class 2?
I retrieve it by http://www.sample.com/myontology#hasLastName
There is something like http://www.sample.com/myontology#Class1#hasLastName ?
Sorry I am a very beginner with Ontology and it is not very clear to me
Assuming you have an ontology as follows:
Datatype: xsd:string
DataProperty: hasLastName
Domain:
Person,
Student
Range:
xsd:string
Class: Person
Class: Student
the following code will retrieve the 2 domains:
IRI lastNamePropertyIRI = IRI.create(ontologyIRI + "#hasLastName");
OWLDataProperty lastNameProperty = dataFactory.getOWLDataProperty(lastNamePropertyIRI);
List<OWLClassExpression> domainClasses =
ontology
.dataPropertyDomainAxioms(lastNameProperty)
.map(OWLDataPropertyDomainAxiom::getDomain)
.collect(Collectors.toList());
for (OWLClassExpression owlClass : domainClasses) {
logger.trace("Domain class = " + owlClass);
}
However, there are some other problems I am concerned with here which relates to the ontology rather than the code.
For the ontology I have given, whenever you specify that an individual john is linked to some surname via hasLastName, the ontology reasoner will infer that john is both a Person and a Student, i.e. the domain of hasLastName is the intersection of Person and Student. Clearly, this is not true for people in general. There are 2 possible solutions to this, depending on your needs:
(1) You can specify that the domain of hasLastName is Person or Student which will take the domain to be the union of Person and Student.
(2) The solution I prefer is to define Student as a subclass of Person and then to state that the domain of hasLastName is the single class Person.
I have a custom content model I created for Alfresco that has type with a d:date property. I am able to build the repository and share projects with seemingly no errors. However, I am unable to search by the properties using the data type d:date or d:int. I resolved the d:int problem by changing the data type to d:text and adding a regex constraint, but I'm not sure if that would be prudent for the d:date property.
Is there some additional configuration that I need to supply or create in order to search by properties that are not d:text?
Here is a snippet showing the type declaration:
<types>
<!-- Enterprise-wide generic document type -->
<type name="gl:x">
<title>Document</title>
<parent>cm:content</parent>
<properties>
<property name="gl:period">
<type>d:text</type>
</property>
<property name="gl:year">
<type>d:text</type>
<constraints>
<constraint ref="gl:documentYears" />
</constraints>
</property>
<property name="gl:docType">
<type>d:text</type>
<constraints>
<constraint ref="gl:documentTypeList" />
</constraints>
</property>
<property name="gl:date">
<type>d:date</type>
</property>
</properties>
</type>
</types>
The share search forms and properties forms seem to be rendering correctly, so I don't think that there is any problem within those.
The advanced search page accepts two types of parameters.
One is simply the "keywords" field. This performs a full text search, i.e. it looks for the provided keywords in ANY text property. There is no need to configure the full text search for custom types (e.g. your gl:x) - it automatically picks up any text property in any model in the system.
The other is the group of single parameters: name, title, description, mime-type, modified-date, modifier. These properties can be of any type. A d:date property would be perfectly acceptable here, as the modified-date parameter testifies.
But here custom properties are not picked-up automatically. They need to be configured explicitly.
Notice that in the upper part of the advanced search page is a drop-down called "Look for" with two options: content and folders. The best approach would be to add an option for your content type gl:x and to configure a search form for it.
You can find the definition of the two standard search forms in tomcat/webapps/share/WEB-INF/classes/alfresco/share-form-config.xml. The file is rather long so here are the two sections to look for:
<config evaluator="model-type" condition="cm:content">
<forms>
<!-- Default Create Content form -->
<form>
</form>
<!-- Document Library Create Google Doc form -->
<form id="doclib-create-googledoc">
</form>
<!-- Search form -->
<form id="search">
</form>
</forms>
</config>
<!-- cm:folder type (creating nodes) -->
<config evaluator="model-type" condition="cm:folder">
<forms>
<!-- Document Library Common form -->
<form id="doclib-common">
</form>
<!-- Search form -->
<form id="search">
</form>
</forms>
</config>
I've skipped the details, but what is important is that "cm:content" and "cm:folder" each defines a <form id="search"> with the desired search properties/parameters.
As an experiment you could modify share-form-config.xml directly and add your own definition:
<config evaluator="model-type" condition="gl:x">
<forms>
<!-- Search form -->
<form id="search">
<field-visibility>
<show id="gl:date" />
</field-visibility>
<appearance>
<field id="gl:date">
<control template="/org/alfresco/components/form/controls/daterange.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
Also you have to add the new search form to the AdvancedSearch configuration found in tomcat/webapps/share/WEB-INF/classes/alfresco/share-config.xml:
<config evaluator="string-compare" condition="AdvancedSearch">
<advanced-search>
<forms>
<form labelId="search.form.label.cm_content" descriptionId="search.form.desc.cm_content">cm:content</form>
<form labelId="search.form.label.cm_folder" descriptionId="search.form.desc.cm_folder">cm:folder</form>
<form labelId="search.form.label.gl_x" descriptionId="search.form.desc.gl_x">gl:x</form>
</forms>
</advanced-search>
</config>
Remember to restart alfresco after every change.
When you're satisfied with the results, it would be better to move your custom definitions to a separate share-config-custom.xml in your project (share-config.xml and share-form-config.xml should never be modified directly).
For more details: https://wiki.alfresco.com/wiki/Share_Advanced_Search
I have a request-map in controller as follows:
<request-map uri="processFirstForm">
<event type="java" path="org.ofbiz.learning.learning.LearningEvents"
invoke="processFirstForm" />
<response name="success" type="view" value="OneFormScreen" />
</request-map>
In controller, I defined a handler for java event as follows:
<handler name="java" type="request" class="org.ofbiz.webapp.event.JavaEventHandler"/>
I have a screen form as follows:
<form name="FirstForm" type="single" target="processFirstForm">
<field name="firstName">
<text />
</field>
<field name="lastName">
<text />
</field>
<field name="submit">
<submit />
</field>
</form>
I also have file LearningEvents.class in folder /bin/org/ofbiz/learning/learning
But i still receive a exception when i submit FirstForm form as follows:
ERROR rendering error page [/error/error.jsp], but here is the error
text: org.ofbiz.webapp.event.EventHandlerException: Error invoking
event, the class org.ofbiz.learning.learning.LearningEvents was not
found
Can anyone help me? thank a lot!
Do you have other java services or events in this component that are working fine? I trying to understand whether the problem is in this event or the whole component setup is not complete. Start from comparing your build.xml and ofbiz-component.xml with an existing one.
I'm using Tapestry 4.
I have several TextFields whose values get passed into Strings in the page class, and they work great as long as there is some content in the fields. Most of them are optional, so I believe I can use the StringTranslator with empty= in that case, but for a couple of fields for which a value is required, I'm having a hard time getting validation to work.
I expected a simple required validator to work:
<component id="myRequiredField" type="TextField">
<binding name="value" value="ognl:stringValue" />
<binding name="validators" value="validators:required" />
</component>
Failing that, I expected minLength to work:
<component id="myRequiredField" type="TextField">
<binding name="value" value="ognl:stringValue" />
<binding name="validators" value="validators:required,minLength=1" />
</component>
Both attempts at validation allow the value as retrieved with getStringValue() to be null upon form submission. My Form and Submit components look like:
<component id="myUpdateForm" type="Form">
<binding name="delegate" value="beans.validationDelegate" />
</component>
<component id="submitUpdate" type="Submit">
<binding name="action" value="listener:doUpdate" />
</component>
It turns out that the validation was working, but I wasn't checking whether my validation delegate had errors before operating on the incoming data. The following seems to be the correct approach to take in any listener that depends on validation, given the setup as listed in the question:
#Bean
public abstract ValidationDelegate getValidationDelegate();
public void doUpdate() {
if (!getValidationDelegate().getHasErrors()) {
// business logic
}
}
I am trying to follow the code for Spring Webflow from 'Spring in Action'. However, when I tried to run the application, I got the following error:
org.springframework.webflow.engine.FlowInputMappingException: Errors occurred during input mapping on startup of the 'pizza' flow; errors = [[RequiredError#13cb4078 mapping = order -> flowScope.order, code = 'required', error = true, errorCause = [null], originalValue = [null], mappedValue = [null]]]
I believe the line that instantiates the order object in the following flow xml is responsible for the exception:
<var name="order" class="com.mycompany.pizza.domain.Order" />
<subflow-state id="customer" subflow="customer-flow">
<input name="order" value="order"/>
<transition on="customerReady" to="buildOrder" />
</subflow-state>
My subflow xml looks like this:
<view-state id="welcome">
<transition on="phoneEntered" to="lookupCustomer" />
</view-state>
<action-state id="lookupCustomer">
<evaluate result="order.customer"
expression="pizzaFlowActions.lookupCustomer(requestParameters.phoneNumber)" />
<transition to="registrationForm"
on-exception="com.mycompany.pizza.service.CustomerNotFoundException" />
<transition to="customerReady" />
</action-state>
Hope there's someone who could point me at the right direction. Thanks!
The error is saying you are REQUIRED to pass a NOT NULL input param/obj "order" to your subflow and you are passing a null value in the order input. So if it is not provided it will throw the exception you see. At the top of your subflow should look something like this:
<input name="order" required="true" type="com.mycompany.pizza.domain.Order"/>
That being said, generally I think when passing pojos between flows/subflows it is good practice to be very explicit and fill out the 'type' attribute in both input tags on the caller of the subflow and the subflow itself and to fill out the scope prefix for the value attribute (e.g flowScope.order)
Moreover, I think your problem is that the <var> tag is NOT initializing your Order pojo that is why it is null it is the equiv of:
Order order = null;
You should explicitly set flowScope.order via a new operator or a factory-method call using the 'set' tag inside an 'on-start' tag in beginning of your parent flow. Something like this:
<on-start>
<set name="flowScope.order" value="new com.mycompany.pizza.domain.Order()"/>
<!-- for development purposes... assuming you are using log4j grab the logger and check that order is in fact NOT null -->
<evaluate expression="T(org.apache.log4j.Logger).getLogger('someLogger').info(flowScope.order)"/>
</on-start>
and then (still inside your parent flow) change your subflow call to look like this:
<subflow-state id="customer" subflow="customer-flow">
<input name="order" value="flowScope.order" type="com.mycompany.pizza.domain.Order"/>
<transition on="customerReady" to="buildOrder" />
</subflow-state>
and... Make sure you also fill out the type attribute inside the input tag of your subflow.xml for order like so:
<input name="order" required="true" type="com.mycompany.pizza.domain.Order"/>