Port legacy persona and emotion replies
This commit is contained in:
@@ -5,12 +5,19 @@ public interface IJiboExperienceContentRepository
|
||||
Task<JiboExperienceCatalog> GetCatalogAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
public sealed class JiboConditionedReply
|
||||
{
|
||||
public string Condition { get; init; } = string.Empty;
|
||||
public string Reply { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class JiboExperienceCatalog
|
||||
{
|
||||
public IReadOnlyList<string> Jokes { get; init; } = [];
|
||||
public IReadOnlyList<string> DanceAnimations { get; init; } = [];
|
||||
public IReadOnlyList<string> GreetingReplies { get; init; } = [];
|
||||
public IReadOnlyList<string> HowAreYouReplies { get; init; } = [];
|
||||
public IReadOnlyList<JiboConditionedReply> EmotionReplies { get; init; } = [];
|
||||
public IReadOnlyList<string> PersonalityReplies { get; init; } = [];
|
||||
public IReadOnlyList<string> PizzaReplies { get; init; } = [];
|
||||
public IReadOnlyList<string> SurpriseReplies { get; init; } = [];
|
||||
|
||||
@@ -152,6 +152,7 @@ internal static class ChitchatStateMachine
|
||||
string loweredTranscript,
|
||||
JiboExperienceCatalog catalog,
|
||||
IJiboRandomizer randomizer,
|
||||
string? currentEmotion,
|
||||
Func<string> buildErrorResponse)
|
||||
{
|
||||
var normalizedLoweredTranscript = NormalizeForPhraseMatching(loweredTranscript);
|
||||
@@ -164,17 +165,82 @@ internal static class ChitchatStateMachine
|
||||
case "robot_personality":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_personality",
|
||||
randomizer.Choose(catalog.PersonalityReplies));
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "curious, playful", "friendly", "personality"));
|
||||
case "robot_taxes":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_taxes",
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "pay anything", "pay taxes", "tax"));
|
||||
case "how_are_you":
|
||||
return BuildEmotionQueryDecision(
|
||||
"how_are_you",
|
||||
randomizer.Choose(catalog.HowAreYouReplies));
|
||||
SelectEmotionQueryReply(catalog, randomizer, currentEmotion));
|
||||
case "robot_desire":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_desire",
|
||||
SelectLegacyPersonalityReply(
|
||||
catalog,
|
||||
randomizer,
|
||||
"socializing and electricity",
|
||||
"want to hang out",
|
||||
"be helpful",
|
||||
"dance from time to time"));
|
||||
case "robot_job":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_job",
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "more fun than a job", "here to help you out"));
|
||||
case "robot_origin_created":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_origin_created",
|
||||
SelectLegacyPersonalityReply(
|
||||
catalog,
|
||||
randomizer,
|
||||
"create something",
|
||||
"some people wanted to create something",
|
||||
"wanted to create something",
|
||||
"built a robot",
|
||||
"came out from a box"));
|
||||
case "robot_origin_from":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_origin_from",
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "boston", "came out from a box"));
|
||||
case "robot_identity":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_identity",
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "am a robot", "i'm either jibo", "i am just jibo"));
|
||||
case "robot_likes_being_jibo":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_likes_being_jibo",
|
||||
SelectLegacyPersonalityReply(
|
||||
catalog,
|
||||
randomizer,
|
||||
"nothing i'd rather be",
|
||||
"love it",
|
||||
"being a human seems so complicated",
|
||||
"especially yours",
|
||||
"steady flow of electricity",
|
||||
"you bet i do"));
|
||||
case "robot_nickname":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_nickname",
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "just jibo", "nickname"));
|
||||
case "robot_name":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_name",
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "no last name", "like Bono", "Jibo."));
|
||||
case "robot_peers":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_peers",
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "one in one million", "others like you"));
|
||||
case "robot_knowledge":
|
||||
return BuildScriptedResponseDecision(
|
||||
"robot_knowledge",
|
||||
SelectLegacyPersonalityReply(catalog, randomizer, "know a lot", "not as much as i will someday"));
|
||||
case "chat":
|
||||
if (IsEmotionQuery(normalizedLoweredTranscript))
|
||||
{
|
||||
return BuildEmotionQueryDecision(
|
||||
"emotion_query",
|
||||
randomizer.Choose(catalog.HowAreYouReplies));
|
||||
SelectEmotionQueryReply(catalog, randomizer, currentEmotion));
|
||||
}
|
||||
|
||||
if (TryResolveEmotionCommand(normalizedLoweredTranscript, out var emotion))
|
||||
@@ -272,10 +338,124 @@ internal static class ChitchatStateMachine
|
||||
[EmotionMetadataKey] = emotion ?? string.Empty,
|
||||
["chitchatLastState"] = IntentSplitState,
|
||||
["chitchatProcessState"] = ProcessQueryState,
|
||||
["chitchatRawTranscript"] = rawTranscript ?? string.Empty
|
||||
["chitchatRawTranscript"] = rawTranscript ?? string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private static string SelectEmotionQueryReply(
|
||||
JiboExperienceCatalog catalog,
|
||||
IJiboRandomizer randomizer,
|
||||
string? currentEmotion)
|
||||
{
|
||||
if (catalog.EmotionReplies.Count == 0)
|
||||
{
|
||||
return randomizer.Choose(catalog.HowAreYouReplies);
|
||||
}
|
||||
|
||||
var emotionVariants = ResolveEmotionVariants(currentEmotion);
|
||||
foreach (var reply in catalog.EmotionReplies)
|
||||
{
|
||||
if (ConditionMatches(reply.Condition, emotionVariants))
|
||||
{
|
||||
return reply.Reply;
|
||||
}
|
||||
}
|
||||
|
||||
return randomizer.Choose(catalog.HowAreYouReplies);
|
||||
}
|
||||
|
||||
private static bool ConditionMatches(string? condition, IReadOnlyList<string> emotionVariants)
|
||||
{
|
||||
var normalizedCondition = NormalizeCondition(condition);
|
||||
if (string.IsNullOrWhiteSpace(normalizedCondition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var clauses = normalizedCondition.Split(new[] { "||" }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
foreach (var clause in clauses)
|
||||
{
|
||||
if (MatchesConditionClause(clause, emotionVariants))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool MatchesConditionClause(string clause, IReadOnlyList<string> emotionVariants)
|
||||
{
|
||||
var normalizedClause = NormalizeCondition(clause).ToUpperInvariant();
|
||||
if (normalizedClause == "!JIBO.EMOTION")
|
||||
{
|
||||
return emotionVariants.Contains(string.Empty, StringComparer.OrdinalIgnoreCase) ||
|
||||
emotionVariants.Contains("NEUTRAL", StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
var equalityIndex = normalizedClause.IndexOf("==", StringComparison.Ordinal);
|
||||
if (equalityIndex < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var rightSide = normalizedClause[(equalityIndex + 2)..].Trim();
|
||||
var candidate = rightSide.Trim('"', '\'');
|
||||
return emotionVariants.Any(variant => string.Equals(variant, candidate, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private static IReadOnlyList<string> ResolveEmotionVariants(string? currentEmotion)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(currentEmotion))
|
||||
{
|
||||
return ["", "NEUTRAL"];
|
||||
}
|
||||
|
||||
var normalizedEmotion = NormalizeCondition(currentEmotion).Trim('"', '\'').ToUpperInvariant();
|
||||
return normalizedEmotion switch
|
||||
{
|
||||
"HAPPY" => ["JOYFUL", "PLEASED", "CONFIDENT", "DETERMINED", "HAPPY"],
|
||||
"SAD" => ["INSECURE", "SAD"],
|
||||
"CALM" => ["NEUTRAL", "INSECURE", "CALM"],
|
||||
"NEUTRAL" => ["NEUTRAL"],
|
||||
"JOYFUL" or "PLEASED" or "CONFIDENT" or "DETERMINED" or "INSECURE" => [normalizedEmotion],
|
||||
_ => [normalizedEmotion]
|
||||
};
|
||||
}
|
||||
|
||||
private static string SelectLegacyPersonalityReply(
|
||||
JiboExperienceCatalog catalog,
|
||||
IJiboRandomizer randomizer,
|
||||
params string[] preferredSnippets)
|
||||
{
|
||||
foreach (var snippet in preferredSnippets)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(snippet))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var match = catalog.PersonalityReplies.FirstOrDefault(reply =>
|
||||
reply.Contains(snippet, StringComparison.OrdinalIgnoreCase));
|
||||
if (!string.IsNullOrWhiteSpace(match))
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
return randomizer.Choose(catalog.PersonalityReplies);
|
||||
}
|
||||
|
||||
private static string NormalizeCondition(string? condition)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(condition))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return PhraseWhitespacePattern.Replace(condition.Trim(), " ");
|
||||
}
|
||||
|
||||
private static bool IsEmotionQuery(string loweredTranscript)
|
||||
{
|
||||
if (ContainsAnyPhrase(loweredTranscript, EmotionQueryPhrases))
|
||||
|
||||
@@ -38,6 +38,9 @@ public sealed class JiboInteractionService(
|
||||
var pendingProactivityOffer = turn.Attributes.TryGetValue("pendingProactivityOffer", out var rawPendingProactivityOffer)
|
||||
? rawPendingProactivityOffer?.ToString()
|
||||
: null;
|
||||
var chitchatEmotion = turn.Attributes.TryGetValue(ChitchatStateMachine.EmotionMetadataKey, out var rawChitchatEmotion)
|
||||
? rawChitchatEmotion?.ToString()
|
||||
: null;
|
||||
var isYesNoTurn = IsYesNoTurn(turn);
|
||||
var greetingPresence = ResolveGreetingPresenceProfile(turn);
|
||||
|
||||
@@ -88,6 +91,7 @@ public sealed class JiboInteractionService(
|
||||
lowered,
|
||||
catalog,
|
||||
randomizer,
|
||||
chitchatEmotion,
|
||||
() => BuildGenericReply(catalog, transcript, lowered));
|
||||
if (chitchatDecision is not null)
|
||||
{
|
||||
@@ -2051,6 +2055,108 @@ public sealed class JiboInteractionService(
|
||||
return "robot_personality";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"do you pay taxes",
|
||||
"do you pay tax",
|
||||
"are you tax exempt"))
|
||||
{
|
||||
return "robot_taxes";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"what do you want",
|
||||
"what is it you want",
|
||||
"what do you really want"))
|
||||
{
|
||||
return "robot_desire";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"what is your job",
|
||||
"what's your job",
|
||||
"what do you do",
|
||||
"what is your work",
|
||||
"what's your work"))
|
||||
{
|
||||
return "robot_job";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"who made you",
|
||||
"who created you",
|
||||
"who built you",
|
||||
"who developed you"))
|
||||
{
|
||||
return "robot_origin_created";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"what are you",
|
||||
"what is jibo",
|
||||
"who are you",
|
||||
"what kind of robot are you"))
|
||||
{
|
||||
return "robot_identity";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"where are you from",
|
||||
"where did you come from",
|
||||
"where were you made"))
|
||||
{
|
||||
return "robot_origin_from";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"what's your name",
|
||||
"what is your name"))
|
||||
{
|
||||
return "robot_name";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"do you have a nickname",
|
||||
"what is your nickname",
|
||||
"what's your nickname"))
|
||||
{
|
||||
return "robot_nickname";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"do you like being jibo",
|
||||
"do you like being yourself",
|
||||
"are you happy being jibo"))
|
||||
{
|
||||
return "robot_likes_being_jibo";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"are there others like you",
|
||||
"are there any others like you",
|
||||
"is there another jibo"))
|
||||
{
|
||||
return "robot_peers";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"how much do you know",
|
||||
"what do you know",
|
||||
"how smart are you"))
|
||||
{
|
||||
return "robot_knowledge";
|
||||
}
|
||||
|
||||
if (MatchesAny(
|
||||
loweredTranscript,
|
||||
"can you order pizza",
|
||||
|
||||
@@ -77,7 +77,7 @@ public static class LegacyMimCatalogImporter
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.Add(bucket.Value, text);
|
||||
builder.Add(bucket.Value, prompt.Condition, text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,11 @@ public static class LegacyMimCatalogImporter
|
||||
return LegacyMimBucket.Personality;
|
||||
}
|
||||
|
||||
if (normalizedPath.Contains("/emotion-responses/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LegacyMimBucket.Emotion;
|
||||
}
|
||||
|
||||
if (normalizedPath.Contains("/scripted-responses/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LegacyMimBucket.Personality;
|
||||
@@ -186,6 +191,7 @@ public static class LegacyMimCatalogImporter
|
||||
DanceAnimations = Merge(baseCatalog.DanceAnimations, importedCatalog.DanceAnimations),
|
||||
GreetingReplies = Merge(baseCatalog.GreetingReplies, importedCatalog.GreetingReplies),
|
||||
HowAreYouReplies = Merge(baseCatalog.HowAreYouReplies, importedCatalog.HowAreYouReplies),
|
||||
EmotionReplies = Merge(baseCatalog.EmotionReplies, importedCatalog.EmotionReplies),
|
||||
PersonalityReplies = Merge(baseCatalog.PersonalityReplies, importedCatalog.PersonalityReplies),
|
||||
PizzaReplies = Merge(baseCatalog.PizzaReplies, importedCatalog.PizzaReplies),
|
||||
SurpriseReplies = Merge(baseCatalog.SurpriseReplies, importedCatalog.SurpriseReplies),
|
||||
@@ -225,11 +231,44 @@ public static class LegacyMimCatalogImporter
|
||||
return merged;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<JiboConditionedReply> Merge(
|
||||
IReadOnlyList<JiboConditionedReply> baseList,
|
||||
IReadOnlyList<JiboConditionedReply> importedList)
|
||||
{
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var merged = new List<JiboConditionedReply>();
|
||||
|
||||
foreach (var value in baseList.Concat(importedList))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value.Reply))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var normalizedCondition = NormalizeCondition(value.Condition);
|
||||
var normalizedReply = value.Reply.Trim();
|
||||
var key = $"{normalizedCondition}::{normalizedReply}";
|
||||
if (!seen.Add(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
merged.Add(new JiboConditionedReply
|
||||
{
|
||||
Condition = normalizedCondition,
|
||||
Reply = normalizedReply
|
||||
});
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
private enum LegacyMimBucket
|
||||
{
|
||||
GenericFallback,
|
||||
Greeting,
|
||||
HowAreYou,
|
||||
Emotion,
|
||||
Personality
|
||||
}
|
||||
|
||||
@@ -237,26 +276,64 @@ public static class LegacyMimCatalogImporter
|
||||
{
|
||||
private readonly List<string> _greetings = [];
|
||||
private readonly List<string> _howAreYous = [];
|
||||
private readonly List<JiboConditionedReply> _emotionReplies = [];
|
||||
private readonly List<string> _personalities = [];
|
||||
private readonly List<string> _fallbacks = [];
|
||||
|
||||
public void Add(LegacyMimBucket bucket, string text)
|
||||
public void Add(LegacyMimBucket bucket, string? condition, string text)
|
||||
{
|
||||
var target = bucket switch
|
||||
switch (bucket)
|
||||
{
|
||||
LegacyMimBucket.GenericFallback => _fallbacks,
|
||||
LegacyMimBucket.Greeting => _greetings,
|
||||
LegacyMimBucket.HowAreYou => _howAreYous,
|
||||
LegacyMimBucket.Personality => _personalities,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(bucket), bucket, null)
|
||||
};
|
||||
case LegacyMimBucket.GenericFallback:
|
||||
if (_fallbacks.Any(value => string.Equals(value, text, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.Any(value => string.Equals(value, text, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
_fallbacks.Add(text);
|
||||
return;
|
||||
case LegacyMimBucket.Greeting:
|
||||
if (_greetings.Any(value => string.Equals(value, text, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_greetings.Add(text);
|
||||
return;
|
||||
case LegacyMimBucket.HowAreYou:
|
||||
if (_howAreYous.Any(value => string.Equals(value, text, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_howAreYous.Add(text);
|
||||
return;
|
||||
case LegacyMimBucket.Emotion:
|
||||
var normalizedCondition = NormalizeCondition(condition);
|
||||
if (_emotionReplies.Any(value =>
|
||||
string.Equals(NormalizeCondition(value.Condition), normalizedCondition, StringComparison.OrdinalIgnoreCase) &&
|
||||
string.Equals(value.Reply, text, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_emotionReplies.Add(new JiboConditionedReply
|
||||
{
|
||||
Condition = normalizedCondition,
|
||||
Reply = text
|
||||
});
|
||||
return;
|
||||
case LegacyMimBucket.Personality:
|
||||
if (_personalities.Any(value => string.Equals(value, text, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_personalities.Add(text);
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(bucket), bucket, null);
|
||||
}
|
||||
|
||||
target.Add(text);
|
||||
}
|
||||
|
||||
public JiboExperienceCatalog Build()
|
||||
@@ -265,6 +342,7 @@ public static class LegacyMimCatalogImporter
|
||||
{
|
||||
GreetingReplies = [.. _greetings],
|
||||
HowAreYouReplies = [.. _howAreYous],
|
||||
EmotionReplies = [.. _emotionReplies],
|
||||
PersonalityReplies = [.. _personalities],
|
||||
GenericFallbackReplies = [.. _fallbacks]
|
||||
};
|
||||
@@ -309,4 +387,14 @@ public static class LegacyMimCatalogImporter
|
||||
[JsonPropertyName("weight")]
|
||||
public int? Weight { get; init; }
|
||||
}
|
||||
|
||||
private static string NormalizeCondition(string? condition)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(condition))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return WhitespacePattern.Replace(condition.Trim(), " ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ public sealed class LegacyMimCatalogImporterTests
|
||||
Assert.Contains("No, I'm one in one million.", catalog.PersonalityReplies);
|
||||
Assert.Contains("I know a lot, I think. But not as much as I will someday.", catalog.PersonalityReplies);
|
||||
Assert.Contains("I don't think of it as a job, because it's more fun than a job. But I'm here to help you out, and have fun with you, and maybe get my head patted by you occasionally.", catalog.PersonalityReplies);
|
||||
Assert.Contains("All systems are go.", catalog.HowAreYouReplies);
|
||||
Assert.Contains(catalog.EmotionReplies, reply =>
|
||||
reply.Condition.Contains("NEUTRAL", StringComparison.OrdinalIgnoreCase) &&
|
||||
reply.Reply.Contains("All systems are go.", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.Contains("A Jibo is a robot. But I'm not just a machine, I have a heart. Well, not a real heart. But feelings. Well, not human feelings. You know what I mean.", catalog.PersonalityReplies);
|
||||
}
|
||||
finally
|
||||
@@ -49,6 +51,9 @@ public sealed class LegacyMimCatalogImporterTests
|
||||
Assert.Contains("I think only you can answer that question.", merged.PersonalityReplies);
|
||||
Assert.Contains("People in Boston made me. It was a pretty cool project.", merged.PersonalityReplies);
|
||||
Assert.Contains("From what I understand, robots don't ever pay anything.", merged.PersonalityReplies);
|
||||
Assert.Contains(merged.EmotionReplies, reply =>
|
||||
reply.Condition.Contains("NEUTRAL", StringComparison.OrdinalIgnoreCase) &&
|
||||
reply.Reply.Contains("All systems are go.", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -64,7 +69,8 @@ public sealed class LegacyMimCatalogImporterTests
|
||||
var catalog = await repository.GetCatalogAsync();
|
||||
|
||||
Assert.Contains("I think only you can answer that question.", catalog.PersonalityReplies);
|
||||
Assert.Contains("All systems are go.", catalog.HowAreYouReplies);
|
||||
Assert.Contains(catalog.EmotionReplies, reply =>
|
||||
reply.Condition.Contains("NEUTRAL", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.Contains("Something's off with the connection to my sources. Maybe ask me again in a little while.", catalog.GenericFallbackReplies);
|
||||
}
|
||||
|
||||
|
||||
@@ -266,6 +266,31 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal("I do. I am curious, playful, and always up for a new experiment.", decision.ReplyText);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("do you pay taxes", "robot_taxes", "From what I understand, robots don't ever pay anything.")]
|
||||
[InlineData("what do you want", "robot_desire", "Socializing and electricity. I'd also be happy if everyone in the world was nicer to each other. It seems like they should be.")]
|
||||
[InlineData("what's your name", "robot_name", "Jibo. Just Jibo, no last name. Like Bono")]
|
||||
[InlineData("who made you", "robot_origin_created", "My story is pretty typical. Some people wanted to create something that would really help people. So they built a robot.")]
|
||||
[InlineData("where are you from", "robot_origin_from", "Some people think I come from the moon. But they're wrong, I'm from Boston.")]
|
||||
public async Task BuildDecisionAsync_LegacyBuildAQuestions_UseImportedScriptedReplies(
|
||||
string transcript,
|
||||
string expectedIntent,
|
||||
string expectedReply)
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = transcript,
|
||||
NormalizedTranscript = transcript
|
||||
});
|
||||
|
||||
Assert.Equal(expectedIntent, decision.IntentName);
|
||||
Assert.Equal(expectedReply, decision.ReplyText);
|
||||
Assert.Null(decision.SkillName);
|
||||
Assert.Equal("ScriptedResponse", decision.ContextUpdates![ChitchatRouteKey]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_Hello_RoutesThroughChitchatScriptedResponse()
|
||||
{
|
||||
@@ -300,6 +325,27 @@ public sealed class JiboInteractionServiceTests
|
||||
Assert.Equal(string.Empty, decision.ContextUpdates[ChitchatEmotionKey]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_AreYouHappy_UsesLegacyEmotionResponseWhenEmotionIsKnown()
|
||||
{
|
||||
var service = CreateService();
|
||||
|
||||
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||
{
|
||||
RawTranscript = "are you happy",
|
||||
NormalizedTranscript = "are you happy",
|
||||
Attributes = new Dictionary<string, object?>
|
||||
{
|
||||
[ChitchatEmotionKey] = "happy"
|
||||
}
|
||||
});
|
||||
|
||||
Assert.Equal("emotion_query", decision.IntentName);
|
||||
Assert.Equal("Yes indeed. Never been better.", decision.ReplyText);
|
||||
Assert.NotNull(decision.ContextUpdates);
|
||||
Assert.Equal("EmotionQuery", decision.ContextUpdates![ChitchatRouteKey]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDecisionAsync_Smile_RoutesThroughEmotionCommandSplit()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user