Personalize how_are_you replies with remembered names
This commit is contained in:
@@ -167,6 +167,7 @@ internal static class ChitchatStateMachine
|
|||||||
JiboExperienceCatalog catalog,
|
JiboExperienceCatalog catalog,
|
||||||
IJiboRandomizer randomizer,
|
IJiboRandomizer randomizer,
|
||||||
string? currentEmotion,
|
string? currentEmotion,
|
||||||
|
string? preferredName,
|
||||||
Func<string> buildErrorResponse)
|
Func<string> buildErrorResponse)
|
||||||
{
|
{
|
||||||
var normalizedLoweredTranscript = NormalizeForPhraseMatching(loweredTranscript);
|
var normalizedLoweredTranscript = NormalizeForPhraseMatching(loweredTranscript);
|
||||||
@@ -187,7 +188,7 @@ internal static class ChitchatStateMachine
|
|||||||
case "how_are_you":
|
case "how_are_you":
|
||||||
return BuildEmotionQueryDecision(
|
return BuildEmotionQueryDecision(
|
||||||
"how_are_you",
|
"how_are_you",
|
||||||
SelectEmotionQueryReply(catalog, randomizer, currentEmotion));
|
SelectEmotionQueryReply(catalog, randomizer, currentEmotion, preferredName));
|
||||||
case "robot_desire":
|
case "robot_desire":
|
||||||
return BuildScriptedResponseDecision(
|
return BuildScriptedResponseDecision(
|
||||||
"robot_desire",
|
"robot_desire",
|
||||||
@@ -285,9 +286,9 @@ internal static class ChitchatStateMachine
|
|||||||
SelectLegacyPersonalityReply(catalog, randomizer, "know a lot", "not as much as i will someday"));
|
SelectLegacyPersonalityReply(catalog, randomizer, "know a lot", "not as much as i will someday"));
|
||||||
case "chat":
|
case "chat":
|
||||||
if (IsEmotionQuery(normalizedLoweredTranscript))
|
if (IsEmotionQuery(normalizedLoweredTranscript))
|
||||||
return BuildEmotionQueryDecision(
|
return BuildEmotionQueryDecision(
|
||||||
"emotion_query",
|
"emotion_query",
|
||||||
SelectEmotionQueryReply(catalog, randomizer, currentEmotion));
|
SelectEmotionQueryReply(catalog, randomizer, currentEmotion, preferredName));
|
||||||
|
|
||||||
if (TryResolveEmotionCommand(normalizedLoweredTranscript, out var emotion))
|
if (TryResolveEmotionCommand(normalizedLoweredTranscript, out var emotion))
|
||||||
return BuildEmotionCommandDecision(randomizer, emotion!);
|
return BuildEmotionCommandDecision(randomizer, emotion!);
|
||||||
@@ -391,16 +392,36 @@ internal static class ChitchatStateMachine
|
|||||||
private static string SelectEmotionQueryReply(
|
private static string SelectEmotionQueryReply(
|
||||||
JiboExperienceCatalog catalog,
|
JiboExperienceCatalog catalog,
|
||||||
IJiboRandomizer randomizer,
|
IJiboRandomizer randomizer,
|
||||||
string? currentEmotion)
|
string? currentEmotion,
|
||||||
|
string? preferredName)
|
||||||
{
|
{
|
||||||
if (catalog.EmotionReplies.Count == 0) return randomizer.Choose(catalog.HowAreYouReplies);
|
if (catalog.EmotionReplies.Count == 0)
|
||||||
|
return PersonalizeHowAreYouReply(randomizer.Choose(catalog.HowAreYouReplies), preferredName);
|
||||||
|
|
||||||
var emotionVariants = ResolveEmotionVariants(currentEmotion);
|
var emotionVariants = ResolveEmotionVariants(currentEmotion);
|
||||||
foreach (var reply in catalog.EmotionReplies)
|
foreach (var reply in catalog.EmotionReplies)
|
||||||
if (ConditionMatches(reply.Condition, emotionVariants))
|
if (ConditionMatches(reply.Condition, emotionVariants))
|
||||||
return reply.Reply;
|
return PersonalizeHowAreYouReply(reply.Reply, preferredName);
|
||||||
|
|
||||||
return randomizer.Choose(catalog.HowAreYouReplies);
|
return PersonalizeHowAreYouReply(randomizer.Choose(catalog.HowAreYouReplies), preferredName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string PersonalizeHowAreYouReply(string replyText, string? preferredName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(replyText) || string.IsNullOrWhiteSpace(preferredName)) return replyText;
|
||||||
|
|
||||||
|
var trimmedName = preferredName.Trim();
|
||||||
|
if (replyText.Contains(trimmedName, StringComparison.OrdinalIgnoreCase)) return replyText;
|
||||||
|
|
||||||
|
var trimmedReply = replyText.Trim();
|
||||||
|
var firstSentenceEnd = trimmedReply.IndexOfAny(['.', '!', '?']);
|
||||||
|
if (firstSentenceEnd <= 0)
|
||||||
|
return $"{trimmedReply}, {trimmedName}.";
|
||||||
|
|
||||||
|
if (firstSentenceEnd == trimmedReply.Length - 1)
|
||||||
|
return $"{trimmedReply[..firstSentenceEnd]}, {trimmedName}.";
|
||||||
|
|
||||||
|
return $"{trimmedReply[..firstSentenceEnd]}, {trimmedName}{trimmedReply[firstSentenceEnd..]}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ConditionMatches(string? condition, IReadOnlyList<string> emotionVariants)
|
private static bool ConditionMatches(string? condition, IReadOnlyList<string> emotionVariants)
|
||||||
|
|||||||
@@ -502,6 +502,7 @@ public sealed partial class JiboInteractionService(
|
|||||||
turnContext => ResolveTenantScope(turnContext));
|
turnContext => ResolveTenantScope(turnContext));
|
||||||
if (householdListDecision is not null) return householdListDecision;
|
if (householdListDecision is not null) return householdListDecision;
|
||||||
|
|
||||||
|
var preferredName = ResolvePreferredGreetingName(turn, greetingPresence);
|
||||||
var chitchatDecision = ChitchatStateMachine.TryBuildDecision(
|
var chitchatDecision = ChitchatStateMachine.TryBuildDecision(
|
||||||
semanticIntent,
|
semanticIntent,
|
||||||
transcript,
|
transcript,
|
||||||
@@ -509,6 +510,7 @@ public sealed partial class JiboInteractionService(
|
|||||||
catalog,
|
catalog,
|
||||||
randomizer,
|
randomizer,
|
||||||
chitchatEmotion,
|
chitchatEmotion,
|
||||||
|
preferredName,
|
||||||
() => BuildGenericReply(catalog, transcript, lowered));
|
() => BuildGenericReply(catalog, transcript, lowered));
|
||||||
if (chitchatDecision is not null) return chitchatDecision;
|
if (chitchatDecision is not null) return chitchatDecision;
|
||||||
|
|
||||||
|
|||||||
@@ -861,6 +861,29 @@ public sealed class JiboInteractionServiceTests
|
|||||||
Assert.Equal("EmotionQuery", decision.ContextUpdates![ChitchatRouteKey]);
|
Assert.Equal("EmotionQuery", decision.ContextUpdates![ChitchatRouteKey]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task BuildDecisionAsync_HowAreYou_UsesRememberedNameForStateDrivenReply()
|
||||||
|
{
|
||||||
|
var memoryStore = new InMemoryPersonalMemoryStore();
|
||||||
|
memoryStore.SetName(new PersonalMemoryTenantScope("acct-how", "loop-how", "device-how"), "jake");
|
||||||
|
var service = CreateService(memoryStore);
|
||||||
|
|
||||||
|
var decision = await service.BuildDecisionAsync(new TurnContext
|
||||||
|
{
|
||||||
|
RawTranscript = "how are you",
|
||||||
|
NormalizedTranscript = "how are you",
|
||||||
|
Attributes = new Dictionary<string, object?>
|
||||||
|
{
|
||||||
|
["accountId"] = "acct-how",
|
||||||
|
["loopId"] = "loop-how"
|
||||||
|
},
|
||||||
|
DeviceId = "device-how"
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Equal("how_are_you", decision.IntentName);
|
||||||
|
Assert.Equal("All systems are go, Jake.", decision.ReplyText);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("what are you up to", "being helpful")]
|
[InlineData("what are you up to", "being helpful")]
|
||||||
[InlineData("what are you doing", "making people smile")]
|
[InlineData("what are you doing", "making people smile")]
|
||||||
|
|||||||
Reference in New Issue
Block a user