Skip to content

Commit

Permalink
Default slot support for templated intents (#11)
Browse files Browse the repository at this point in the history
* Updated ver num.

* Added default value slot support to templated intents.

* Added customslot with default value.

* More work on making templated intents default value aware.
  • Loading branch information
rabidgremlin authored Jul 31, 2018
1 parent 18a5baf commit 42fb90f
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 18 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=4.2.1
version=4.3.0-SNAPSHOT

# These are place holder values. Real values should be set in user's home gradle.properties
# and are only needed when signing and uploading to central maven repo
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.rabidgremlin.mutters.core.ml;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;
import java.util.SortedMap;
Expand Down Expand Up @@ -86,6 +88,16 @@ public void addIntent(Intent intent)
{
intents.put(intent.getName().toUpperCase(), intent);
}

/**
* Returns the intents for this matcher.
*
* @return The intents for this matcher
*/
public Collection<Intent> getIntents()
{
return Collections.unmodifiableCollection(intents.values());
}

/*
* (non-Javadoc)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rabidgremlin.mutters.core.IntentMatch;
import com.rabidgremlin.mutters.core.SlotMatch;
Expand All @@ -17,6 +19,9 @@
*/
public class SessionUtils
{
/** Logger.*/
private static final Logger LOG = LoggerFactory.getLogger(SessionUtils.class);

/** Prefix for slot values stored in session to avoid any name collisions. */
public static final String SLOT_PREFIX = "SLOT_JLA1974_";

Expand Down Expand Up @@ -163,8 +168,16 @@ public static String getStringSlot(IntentMatch match, String slotName, String de
{
if (match.getSlotMatch(slotName) != null && match.getSlotMatch(slotName).getValue() != null)
{
// TODO better cast handling
return (String) match.getSlotMatch(slotName).getValue();
try
{
return (String) match.getSlotMatch(slotName).getValue();
}
catch(ClassCastException e)
{
// failed to cast so assume invalid string and return default
LOG.warn("Non String value: {} found in slot {}", match.getSlotMatch(slotName).getValue(), slotName);
return defaultValue;
}
}
else
{
Expand All @@ -184,8 +197,16 @@ public static Number getNumberSlot(IntentMatch match, String slotName, Number de
{
if (match.getSlotMatch(slotName) != null && match.getSlotMatch(slotName).getValue() != null)
{
// TODO better cast handling
return (Number) match.getSlotMatch(slotName).getValue();
try
{
return (Number) match.getSlotMatch(slotName).getValue();
}
catch(ClassCastException e)
{
// failed to cast so assume invalid number and return default
LOG.warn("Non Number value: {} found in slot {}", match.getSlotMatch(slotName).getValue(), slotName);
return defaultValue;
}
}
else
{
Expand All @@ -206,8 +227,16 @@ public static LocalDate getLocalDateSlot(IntentMatch match, String slotName,
{
if (match.getSlotMatch(slotName) != null && match.getSlotMatch(slotName).getValue() != null)
{
// TODO better cast handling
return (LocalDate) match.getSlotMatch(slotName).getValue();
try
{
return (LocalDate) match.getSlotMatch(slotName).getValue();
}
catch(ClassCastException e)
{
// failed to cast so assume invalid localdate and return default
LOG.warn("Non LocalDate value: {} found in slot {}", match.getSlotMatch(slotName).getValue(), slotName);
return defaultValue;
}
}
else
{
Expand All @@ -228,8 +257,16 @@ public static LocalTime getLocalTimeSlot(IntentMatch match, String slotName,
{
if (match.getSlotMatch(slotName) != null && match.getSlotMatch(slotName).getValue() != null)
{
// TODO better cast handling
return (LocalTime) match.getSlotMatch(slotName).getValue();
try
{
return (LocalTime) match.getSlotMatch(slotName).getValue();
}
catch(ClassCastException e)
{
// failed to cast so assume invalid localtime and return default
LOG.warn("Non LocalTime value: {} found in slot {}", match.getSlotMatch(slotName).getValue(), slotName);
return defaultValue;
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.rabidgremlin.mutters.slots;

import java.util.HashMap;

import com.rabidgremlin.mutters.core.Context;
import com.rabidgremlin.mutters.core.Slot;
import com.rabidgremlin.mutters.core.SlotMatch;

/**
* A CustomSlot that supports default values.
*
* @author rabidgremlin
*
*/
public class CustomSlotWithDefaultValue
extends CustomSlot
implements DefaultValueSlot
{
/** The default value to return */
private Object defaultValue;

/**
* Constructor.
*
* @param name The name of the slot.
* @param optionValueMap A map of possible input values mapped to output values.
* @param defaultValue The default value.
*/
public CustomSlotWithDefaultValue(String name, HashMap<String, String> optionValueMap, Object defaultValue)
{
super(name, optionValueMap);
this.defaultValue = defaultValue;
}

/**
* Constructor.
*
* @param name The name of the slot.
* @param options The list of expected options.
* @param defaultValue The default value.
*/
public CustomSlotWithDefaultValue(String name, String[] options, Object defaultValue)
{
super(name, options);
this.defaultValue = defaultValue;
}

@Override
public Object getDefaultValue()
{
return defaultValue;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rabidgremlin.mutters.core.Context;
import com.rabidgremlin.mutters.core.Intent;
import com.rabidgremlin.mutters.core.Slot;
import com.rabidgremlin.mutters.core.SlotMatch;
import com.rabidgremlin.mutters.core.Tokenizer;
import com.rabidgremlin.mutters.slots.DefaultValueSlot;

/**
* This is an intent that matches based on an utterance template.
Expand Down Expand Up @@ -81,21 +85,35 @@ public List<TemplatedUtterance> addUtterances(List<String> utteranceTemplates)
* @return The templated utterance match.
*/
public TemplatedUtteranceMatch matches(String[] input, Context context)
{
log.debug("------------- Intent: {} Input: {}", name, input);
{
for (TemplatedUtterance utterance : utterances)
{
log.debug(" Matching to {} ", utterance.getTemplate());
{
TemplatedUtteranceMatch match = utterance.matches(input, slots, context);
if (match.isMatched())
{
log.debug("------------ Matched to {} match: {} -------------", utterance.getTemplate(),
match);
{
// matched utterance didn't fill in all the slots so check for default values
if (match.getSlotMatches().size() != slots.getSlots().size())
{
// grab all the matched slots
HashMap<Slot, SlotMatch> matchedSlots = match.getSlotMatches();

// loop through each slot
for (Slot slot: slots.getSlots())
{
// does slot have default value and no match ?
if (slot instanceof DefaultValueSlot && !matchedSlots.containsKey(slot))
{
// yep create a slot match with default value
Object defaultValue = ((DefaultValueSlot)slot).getDefaultValue();
matchedSlots.put(slot, new SlotMatch(slot,defaultValue == null?"":defaultValue.toString(),defaultValue));
}
}
}

return match;
}
}

log.debug("------------ No Match to {} -------------", name);

return new TemplatedUtteranceMatch(false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.rabidgremlin.mutters.core.IntentMatch;
import com.rabidgremlin.mutters.core.SlotMatch;
import com.rabidgremlin.mutters.slots.CustomSlot;
import com.rabidgremlin.mutters.slots.DefaultValueSlot;
import com.rabidgremlin.mutters.slots.LiteralSlot;
import com.rabidgremlin.mutters.slots.NumberSlot;
import com.rabidgremlin.mutters.templated.SimpleTokenizer;
Expand Down Expand Up @@ -117,5 +118,58 @@ public void testHandlingOfEmptyOrTokenizedOutInputs()
intentMatch = matcher.match(" ?", new Context(), null, null);
assertThat(intentMatch, is(nullValue()));
}

// slot that matches a colour or defaults to black
class ColorsSlot extends CustomSlot implements DefaultValueSlot
{
public ColorsSlot()
{
super("Color",new String[] {"Red","Green","Blue","White"});
}

@Override
public Object getDefaultValue()
{
return "Black";
}
}

@Test
public void testDefaultValueHandling()
{
TemplatedIntentMatcher matcher = new TemplatedIntentMatcher(tokenizer);

TemplatedIntent intent = matcher.addIntent("FavColourIntent");

ColorsSlot colorSlot = new ColorsSlot();
intent.addSlot(colorSlot);

intent.addUtterance("My favourite color is {Color}");
intent.addUtterance("{Color} is my favourite");
intent.addUtterance("I have a favourite color"); // utterance without a slot, should default to Black

IntentMatch intentMatch = matcher.match("My favourite color is green", new Context(), null, null);
assertThat(intentMatch, is(notNullValue()));
assertThat(intentMatch.getSlotMatches().size(), is(1));
SlotMatch colourMatch = intentMatch.getSlotMatches().get(colorSlot);
assertThat(colourMatch, is(notNullValue()));
assertThat(colourMatch.getValue(), is("Green"));

intentMatch = matcher.match("Red is my favourite", new Context(), null, null);
assertThat(intentMatch, is(notNullValue()));
assertThat(intentMatch.getSlotMatches().size(), is(1));
colourMatch = intentMatch.getSlotMatches().get(colorSlot);
assertThat(colourMatch, is(notNullValue()));
assertThat(colourMatch.getValue(), is("Red"));


intentMatch = matcher.match("I have a favourite color", new Context(), null, null);
assertThat(intentMatch, is(notNullValue()));
assertThat(intentMatch.getSlotMatches().size(), is(1));
colourMatch = intentMatch.getSlotMatches().get(colorSlot);
assertThat(colourMatch, is(notNullValue()));
assertThat(colourMatch.getValue(), is("Black"));

}

}

0 comments on commit 42fb90f

Please sign in to comment.