All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.rrd.wool.execution.ActiveWoolDialogue Maven / Gradle / Ivy

Go to download

WOOL is a simple, powerful dialogue framework for creating virtual agent conversations.

The newest version!
/*
 * Copyright 2019 Roessingh Research and Development.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a 
 * copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 * and/or sell copies of the Software, and to permit persons to whom the 
 * Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */

package nl.rrd.wool.execution;

import nl.rrd.wool.exception.WoolException;
import nl.rrd.wool.expressions.EvaluationException;
import nl.rrd.wool.model.*;
import nl.rrd.wool.model.command.WoolCommand;
import nl.rrd.wool.model.command.WoolInputCommand;
import nl.rrd.wool.model.command.WoolSetCommand;
import nl.rrd.wool.model.nodepointer.WoolNodePointer;
import nl.rrd.wool.model.nodepointer.WoolNodePointerInternal;
import org.joda.time.DateTime;

import java.util.List;
import java.util.Map;

/**
 * An {@link ActiveWoolDialogue} is a wrapper around a {@link WoolDialogue}, which contains
 * a static definition of a dialogue (referred to as the {@code dialogueDefinition}). 
 * The {@link ActiveWoolDialogue} also contains utility functions to keep track of the state during 
 * "execution" of the dialogue.
 * 
 * @author Harm op den Akker
 * @author Tessa Beinema
 */
public class ActiveWoolDialogue {

	private WoolDialogueDescription dialogueDescription;
	private WoolDialogue dialogueDefinition;
	private WoolNode currentNode;
	private DialogueState dialogueState;
	private WoolVariableStore woolVariableStore;
		
	// ----------- Constructors:
	
	public ActiveWoolDialogue(WoolDialogueDescription dialogueDescription,
			WoolDialogue dialogueDefinition) {
		this.dialogueDescription = dialogueDescription;
		this.dialogueDefinition = dialogueDefinition;
		this.dialogueState = DialogueState.INACTIVE;
	}
	
	// ---------- Getters:

	public WoolDialogueDescription getDialogueDescription() {
		return dialogueDescription;
	}

	public WoolDialogue getDialogueDefinition() {
		return dialogueDefinition;
	}
	
	public WoolNode getCurrentNode() {
		return currentNode;
	}
	
	public DialogueState getDialogueState() {
		return dialogueState;
	}
	
	/**
	 * Returns the {@link WoolVariableStore} associated with this {@link ActiveWoolDialogue}.
	 * @return the {@link WoolVariableStore} associated with this {@link ActiveWoolDialogue}.
	 */
	public WoolVariableStore getWoolVariableStore() {
		return woolVariableStore;
	}
	
	// ---------- Setters:
	
	public void setCurrentNode(WoolNode currentNode) {
		this.currentNode = currentNode;
	}
	
	public void setDialogueState(DialogueState dialogueState) {
		this.dialogueState = dialogueState;
	}
	
	/**
	 * Sets the {@link WoolVariableStore} used to store/retrieve parameters for this {@link ActiveWoolDialogue}.
	 * @param woolVariableStore the {@link WoolVariableStore} used to store/retrieve parameters for this {@link ActiveWoolDialogue}.
	 */
	public void setWoolVariableStore(WoolVariableStore woolVariableStore) {
		this.woolVariableStore = woolVariableStore;
	}
	
	// ---------- Convenience:
	
	/**
	 * Returns the name of this {@link ActiveWoolDialogue} as defined in the associated {@link WoolDialogue}.
	 * @return the name of this {@link ActiveWoolDialogue} as defined in the associated {@link WoolDialogue}.
	 */
	public String getDialogueName() {
		return dialogueDefinition.getDialogueName();
	}
	
	// ---------- Functions:
	
	/**
	 * "Starts" this {@link ActiveWoolDialogue}, returning the start node and
	 * updating its internal state.
	 * 
	 * @param time the time in the time zone of the user. This will be stored
	 * with changes in the variable store.
	 * @return the initial {@link WoolNode}.
	 * @throws WoolException if the request is invalid
	 * @throws EvaluationException if an expression cannot be evaluated
	 */
	public WoolNode startDialogue(DateTime time) throws WoolException,
			EvaluationException {
		return startDialogue(null, time);
	}
	
	/**
	 * "Starts" this {@link ActiveWoolDialogue} at the provided {@link
	 * WoolNode}, returning that node and updating the dialogue's internal
	 * state. If you set the nodeId to null, it will return the start node.
	 *
	 * @param nodeId the node ID or null
	 * @param time the time in the time zone of the user. This will be stored
	 * with changes in the variable store.
	 * @return the {@link WoolNode}
	 * @throws WoolException if the request is invalid
	 * @throws EvaluationException if an expression cannot be evaluated
	 */
	public WoolNode startDialogue(String nodeId, DateTime time)
			throws WoolException, EvaluationException {
		this.dialogueState = DialogueState.ACTIVE;
		WoolNode nextNode;
		if (nodeId == null) {
			nextNode = dialogueDefinition.getStartNode();
		} else {
			nextNode = dialogueDefinition.getNodeById(nodeId);
			if (nextNode == null) {
				throw new WoolException(WoolException.Type.NODE_NOT_FOUND,
						String.format("Node \"%s\" not found in dialogue \"%s\"",
								nodeId, dialogueDefinition.getDialogueName()));
			}
		}
		this.currentNode = executeWoolNode(nextNode, time);
		if (this.currentNode.getBody().getReplies().size() == 0)
			this.dialogueState = DialogueState.FINISHED;
		return currentNode;
	}
	
	/**
	 * Retrieves the pointer to the next node based on the provided reply id.
	 * This might be a pointer to the end node. This method also performs any
	 * "set" actions associated with the reply.
	 * 
	 * @param replyId the reply ID
	 * @param time the time in the time zone of the user
	 * @return WoolNodePointer the pointer to the next node
	 * @throws EvaluationException if an expression cannot be evaluated
	 */
	public WoolNodePointer processReplyAndGetNodePointer(int replyId,
			DateTime time) throws EvaluationException {
		WoolReply selectedWoolReply = currentNode.getBody().findReplyById(
				replyId);
		Map variableMap = woolVariableStore.getModifiableMap(
				true, time);
		for (WoolCommand command : selectedWoolReply.getCommands()) {
			if (command instanceof WoolSetCommand) {
				WoolSetCommand setCommand = (WoolSetCommand)command;
				setCommand.getExpression().evaluate(variableMap);
			}
		}
		return selectedWoolReply.getNodePointer();
	}
	
	/**
	 * Takes the next node pointer from the selected reply and determines the
	 * next node. The pointer might point to the end note, which means that
	 * there is no next node. If there is no next node, or the next node has no
	 * reply options, then the dialogue is considered finished.
	 * 
	 * 

If there is a next node, then it returns the executed version of that * next {@link WoolNode} which results from a call to the {@link * #executeWoolNode(WoolNode, DateTime)} function.

* * @param nodePointer the next node pointer from the selected reply * @param time the time in the time zone of the user. This will be stored * with changes in the variable store. * @return the next {@link WoolNode} that follows on the selected reply or * null * @throws EvaluationException if an expression cannot be evaluated */ public WoolNode progressDialogue(WoolNodePointerInternal nodePointer, DateTime time) throws EvaluationException { WoolNode nextNode = null; if (!nodePointer.getNodeId().toLowerCase().equals("end")) nextNode = dialogueDefinition.getNodeById(nodePointer.getNodeId()); this.currentNode = nextNode; if (nextNode == null || nextNode.getBody().getReplies().isEmpty()) this.dialogueState = DialogueState.FINISHED; if (nextNode != null) this.currentNode = executeWoolNode(nextNode, time); return currentNode; } /** * Stores the specified variables in the variable store. * * @param variables the variables * @param time the time in the time zone of the user */ public void storeReplyInput(Map variables, DateTime time) { Map map = woolVariableStore.getModifiableMap(true, time); map.putAll(variables); } /** * The user's client returned the given {@code replyId} - what was the * statement that was uttered by the user? * * @param replyId the reply ID * @return the statement * @throws WoolException if no reply with the specified ID is found */ public String getUserStatementFromReplyId(int replyId) throws WoolException { WoolReply selectedReply = currentNode.getBody().findReplyById(replyId); if (selectedReply == null) { throw new WoolException(WoolException.Type.REPLY_NOT_FOUND, String.format("Reply with ID %s not found in dialogue \"%s\", node \"%s\"", replyId, dialogueDefinition.getDialogueName(), currentNode.getTitle())); } if (selectedReply.getStatement() == null) return "AUTOFORWARD"; StringBuilder result = new StringBuilder(); List segments = selectedReply.getStatement() .getSegments(); for (WoolNodeBody.Segment segment : segments) { if (segment instanceof WoolNodeBody.TextSegment) { WoolNodeBody.TextSegment textSegment = (WoolNodeBody.TextSegment)segment; result.append(textSegment.getText().evaluate(null)); } else { WoolNodeBody.CommandSegment cmdSegment = (WoolNodeBody.CommandSegment)segment; // a reply statement can only contain an "input" command WoolInputCommand command = (WoolInputCommand)cmdSegment.getCommand(); result.append(command.getStatementLog(woolVariableStore)); } } return result.toString(); } /** * Executes the agent statement and reply statements in the specified node * with respect to the specified variable map. It executes ("if" and "set") * commands and resolves variables. Any resulting body content that should * be sent to the client, is added to the (agent or reply) statement body in * the resulting node. This content can be text or client commands, with all * variables resolved. * * @param woolNode a node to execute * @param time the time in the time zone of the user. This will be stored * with changes in the variable store. * @return the executed WoolNode * @throws EvaluationException if an expression cannot be evaluated */ private WoolNode executeWoolNode(WoolNode woolNode, DateTime time) throws EvaluationException { WoolNode processedNode = new WoolNode(); processedNode.setHeader(woolNode.getHeader()); WoolNodeBody processedBody = new WoolNodeBody(); Map variables = woolVariableStore.getModifiableMap(true, time); woolNode.getBody().execute(variables, true, processedBody); processedNode.setBody(processedBody); return processedNode; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy