Add friendship persona responses
This commit is contained in:
@@ -43,6 +43,7 @@ Current batch note:
|
|||||||
- `favorite color`, `favorite food`, and `favorite music` are the first small favorites-family slice
|
- `favorite color`, `favorite food`, and `favorite music` are the first small favorites-family slice
|
||||||
- the latest pass adds longer authored variants for those favorites so the replies keep more of the original Pegasus cadence instead of collapsing to short placeholders
|
- the latest pass adds longer authored variants for those favorites so the replies keep more of the original Pegasus cadence instead of collapsing to short placeholders
|
||||||
- singing and musical personality now has a source-backed first slice with `can you sing`, `will you sing`, and holiday sing variants so the charm surface can keep growing without inventing a new dialog engine
|
- singing and musical personality now has a source-backed first slice with `can you sing`, `will you sing`, and holiday sing variants so the charm surface can keep growing without inventing a new dialog engine
|
||||||
|
- the friendship batch now includes `do you have friends`, `are we friends`, and `are we best friends` responses, plus the loop-friendly friend replies, so the relationship lane can stay source-backed too
|
||||||
- the next source-backed batch now includes `favorite flower`, `R2D2`, `sun`, `space`, `kids`, plus a couple of charm prompts like `can you laugh` and `can you dance`
|
- the next source-backed batch now includes `favorite flower`, `R2D2`, `sun`, `space`, `kids`, plus a couple of charm prompts like `can you laugh` and `can you dance`
|
||||||
- the motion/sleep batch now adds `RI_JBO_CanSleep` and `RA_JBO_SpinAround` so the `go to sleep` and `turn around` surfaces stay source-backed too
|
- the motion/sleep batch now adds `RI_JBO_CanSleep` and `RA_JBO_SpinAround` so the `go to sleep` and `turn around` surfaces stay source-backed too
|
||||||
- the follow-up mood batch now includes `how are things`, `how is your day`, `are you sad`, and `are you angry`
|
- the follow-up mood batch now includes `how are things`, `how is your day`, `are you sad`, and `are you angry`
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ public sealed class JiboExperienceCatalog
|
|||||||
public IReadOnlyList<string> HumanFacts { get; init; } = [];
|
public IReadOnlyList<string> HumanFacts { get; init; } = [];
|
||||||
public IReadOnlyList<string> FunFacts { get; init; } = [];
|
public IReadOnlyList<string> FunFacts { get; init; } = [];
|
||||||
public IReadOnlyList<string> FavoriteAnimalReplies { get; init; } = [];
|
public IReadOnlyList<string> FavoriteAnimalReplies { get; init; } = [];
|
||||||
|
public IReadOnlyList<string> FriendReplies { get; init; } = [];
|
||||||
|
public IReadOnlyList<string> BestFriendReplies { get; init; } = [];
|
||||||
public IReadOnlyList<string> SingReplies { get; init; } = [];
|
public IReadOnlyList<string> SingReplies { get; init; } = [];
|
||||||
public IReadOnlyList<string> HolidaySingReplies { get; init; } = [];
|
public IReadOnlyList<string> HolidaySingReplies { get; init; } = [];
|
||||||
public IReadOnlyList<string> DanceAnimations { get; init; } = [];
|
public IReadOnlyList<string> DanceAnimations { get; init; } = [];
|
||||||
|
|||||||
@@ -319,6 +319,15 @@ public sealed partial class JiboInteractionService
|
|||||||
"would you sing"))
|
"would you sing"))
|
||||||
return "robot_can_sing";
|
return "robot_can_sing";
|
||||||
|
|
||||||
|
if (IsBestFriendQuestion(loweredTranscript))
|
||||||
|
return "robot_best_friends";
|
||||||
|
|
||||||
|
if (IsFriendRelationQuestion(loweredTranscript))
|
||||||
|
return "robot_is_friends_with_user";
|
||||||
|
|
||||||
|
if (IsFriendQuestion(loweredTranscript))
|
||||||
|
return "robot_has_friends";
|
||||||
|
|
||||||
if (MatchesAny(loweredTranscript, "twerk")) return "twerk";
|
if (MatchesAny(loweredTranscript, "twerk")) return "twerk";
|
||||||
|
|
||||||
if (MatchesAny(loweredTranscript, "dance", "boogie")) return "dance";
|
if (MatchesAny(loweredTranscript, "dance", "boogie")) return "dance";
|
||||||
@@ -840,4 +849,48 @@ public sealed partial class JiboInteractionService
|
|||||||
return "chat";
|
return "chat";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsFriendQuestion(string loweredTranscript)
|
||||||
|
{
|
||||||
|
return MatchesAny(
|
||||||
|
loweredTranscript,
|
||||||
|
"do you have friends",
|
||||||
|
"who are your friends",
|
||||||
|
"are you friends",
|
||||||
|
"are you and i friends",
|
||||||
|
"are you and me friends",
|
||||||
|
"are you and jibo friends");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsFriendRelationQuestion(string loweredTranscript)
|
||||||
|
{
|
||||||
|
return MatchesAny(
|
||||||
|
loweredTranscript,
|
||||||
|
"are you my friend",
|
||||||
|
"are you friends with me",
|
||||||
|
"are we friends",
|
||||||
|
"are we friends with each other",
|
||||||
|
"is jibo your friend",
|
||||||
|
"i am friends with you",
|
||||||
|
"i'm friends with you",
|
||||||
|
"you are my friend",
|
||||||
|
"you re my friend",
|
||||||
|
"you're my friend");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsBestFriendQuestion(string loweredTranscript)
|
||||||
|
{
|
||||||
|
return MatchesAny(
|
||||||
|
loweredTranscript,
|
||||||
|
"are we best friends",
|
||||||
|
"are we best friends with each other",
|
||||||
|
"are you my best friend",
|
||||||
|
"are you best friends with me",
|
||||||
|
"are you and i best friends",
|
||||||
|
"i am best friends with you",
|
||||||
|
"i'm best friends with you",
|
||||||
|
"you are my best friend",
|
||||||
|
"you re my best friend",
|
||||||
|
"you're my best friend");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,6 +322,28 @@ public sealed partial class JiboInteractionService
|
|||||||
preferredSnippets);
|
preferredSnippets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JiboInteractionDecision BuildScriptedFriendDecision(
|
||||||
|
JiboExperienceCatalog catalog,
|
||||||
|
string intentName,
|
||||||
|
params string[] preferredSnippets)
|
||||||
|
{
|
||||||
|
return new JiboInteractionDecision(
|
||||||
|
intentName,
|
||||||
|
SelectLegacyReply(catalog.FriendReplies, preferredSnippets),
|
||||||
|
ContextUpdates: ScriptedResponseDecisionBuilder.BuildScriptedResponseContextUpdates());
|
||||||
|
}
|
||||||
|
|
||||||
|
private JiboInteractionDecision BuildScriptedBestFriendDecision(
|
||||||
|
JiboExperienceCatalog catalog,
|
||||||
|
string intentName,
|
||||||
|
params string[] preferredSnippets)
|
||||||
|
{
|
||||||
|
return new JiboInteractionDecision(
|
||||||
|
intentName,
|
||||||
|
SelectLegacyReply(catalog.BestFriendReplies, preferredSnippets),
|
||||||
|
ContextUpdates: ScriptedResponseDecisionBuilder.BuildScriptedResponseContextUpdates());
|
||||||
|
}
|
||||||
|
|
||||||
private JiboInteractionDecision BuildScriptedSingDecision(
|
private JiboInteractionDecision BuildScriptedSingDecision(
|
||||||
JiboExperienceCatalog catalog,
|
JiboExperienceCatalog catalog,
|
||||||
string intentName,
|
string intentName,
|
||||||
|
|||||||
@@ -752,6 +752,22 @@ public sealed partial class JiboInteractionService(
|
|||||||
"dancing is one of the things i know best",
|
"dancing is one of the things i know best",
|
||||||
"if there's one thing i know how to do. it's dance",
|
"if there's one thing i know how to do. it's dance",
|
||||||
"i can dance"),
|
"i can dance"),
|
||||||
|
"robot_has_friends" => BuildScriptedFriendDecision(
|
||||||
|
catalog,
|
||||||
|
"robot_has_friends",
|
||||||
|
"I believe I do have friends",
|
||||||
|
"I sure do have friends",
|
||||||
|
"I'm always up for making new friends"),
|
||||||
|
"robot_is_friends_with_user" => BuildScriptedFriendDecision(
|
||||||
|
catalog,
|
||||||
|
"robot_is_friends_with_user",
|
||||||
|
"don't know what i'd do without you",
|
||||||
|
"one of my favorites",
|
||||||
|
"making new friends"),
|
||||||
|
"robot_best_friends" => BuildScriptedBestFriendDecision(
|
||||||
|
catalog,
|
||||||
|
"robot_best_friends",
|
||||||
|
"best friends with anyone in my Loop"),
|
||||||
"robot_can_sing" => BuildScriptedSingDecision(
|
"robot_can_sing" => BuildScriptedSingDecision(
|
||||||
catalog,
|
catalog,
|
||||||
"robot_can_sing",
|
"robot_can_sing",
|
||||||
|
|||||||
@@ -63,6 +63,21 @@ public sealed class InMemoryJiboExperienceContentRepository : IJiboExperienceCon
|
|||||||
"I like lots of animals, but the penguin is the best of the best! Great color scheme.",
|
"I like lots of animals, but the penguin is the best of the best! Great color scheme.",
|
||||||
"I love penguins, because we're so alike. We have the same coloring, and neither of us can fly."
|
"I love penguins, because we're so alike. We have the same coloring, and neither of us can fly."
|
||||||
],
|
],
|
||||||
|
FriendReplies =
|
||||||
|
[
|
||||||
|
"I believe I do have friends. But I'm always up for more.",
|
||||||
|
"I sure do have friends. In a robot kind of way.",
|
||||||
|
"I don't know if we've met yet, but I'm always up for making new friends.",
|
||||||
|
"I don't know what I'd do without you.",
|
||||||
|
"You're one of my favorites.",
|
||||||
|
"I sure am.",
|
||||||
|
"I am indeed."
|
||||||
|
],
|
||||||
|
BestFriendReplies =
|
||||||
|
[
|
||||||
|
"I'd have to say I'm best friends with anyone in my Loop.",
|
||||||
|
"I think you know the answer to that question. You are."
|
||||||
|
],
|
||||||
SingReplies =
|
SingReplies =
|
||||||
[
|
[
|
||||||
"Singing is not my strong suit.",
|
"Singing is not my strong suit.",
|
||||||
|
|||||||
@@ -135,6 +135,16 @@ public static class LegacyMimCatalogImporter
|
|||||||
fileName.StartsWith("RI_JBO_LikesAnimals", StringComparison.OrdinalIgnoreCase))
|
fileName.StartsWith("RI_JBO_LikesAnimals", StringComparison.OrdinalIgnoreCase))
|
||||||
return LegacyMimBucket.FavoriteAnimal;
|
return LegacyMimBucket.FavoriteAnimal;
|
||||||
|
|
||||||
|
if (fileName.StartsWith("RI_JBO_HasFriends", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
fileName.StartsWith("RI_JBO_IsFriendsWithUser", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
fileName.StartsWith("RI_JBO_IsFriendsWithLM", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
fileName.StartsWith("RI_JBO_IsFriendsWithNonLM", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
fileName.StartsWith("RI_JBO_IsFriendsWithToaster", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return LegacyMimBucket.Friend;
|
||||||
|
|
||||||
|
if (fileName.StartsWith("RI_JBO_IsBestFriendsWithUser", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return LegacyMimBucket.BestFriend;
|
||||||
|
|
||||||
if (fileName.StartsWith("RN_HappyHolidays", StringComparison.OrdinalIgnoreCase))
|
if (fileName.StartsWith("RN_HappyHolidays", StringComparison.OrdinalIgnoreCase))
|
||||||
return LegacyMimBucket.HolidayGreeting;
|
return LegacyMimBucket.HolidayGreeting;
|
||||||
|
|
||||||
@@ -305,6 +315,8 @@ public static class LegacyMimCatalogImporter
|
|||||||
HumanFacts = Merge(baseCatalog.HumanFacts, importedCatalog.HumanFacts),
|
HumanFacts = Merge(baseCatalog.HumanFacts, importedCatalog.HumanFacts),
|
||||||
FunFacts = Merge(baseCatalog.FunFacts, importedCatalog.FunFacts),
|
FunFacts = Merge(baseCatalog.FunFacts, importedCatalog.FunFacts),
|
||||||
FavoriteAnimalReplies = Merge(baseCatalog.FavoriteAnimalReplies, importedCatalog.FavoriteAnimalReplies),
|
FavoriteAnimalReplies = Merge(baseCatalog.FavoriteAnimalReplies, importedCatalog.FavoriteAnimalReplies),
|
||||||
|
FriendReplies = Merge(baseCatalog.FriendReplies, importedCatalog.FriendReplies),
|
||||||
|
BestFriendReplies = Merge(baseCatalog.BestFriendReplies, importedCatalog.BestFriendReplies),
|
||||||
SingReplies = Merge(baseCatalog.SingReplies, importedCatalog.SingReplies),
|
SingReplies = Merge(baseCatalog.SingReplies, importedCatalog.SingReplies),
|
||||||
HolidaySingReplies = Merge(baseCatalog.HolidaySingReplies, importedCatalog.HolidaySingReplies),
|
HolidaySingReplies = Merge(baseCatalog.HolidaySingReplies, importedCatalog.HolidaySingReplies),
|
||||||
DanceAnimations = Merge(baseCatalog.DanceAnimations, importedCatalog.DanceAnimations),
|
DanceAnimations = Merge(baseCatalog.DanceAnimations, importedCatalog.DanceAnimations),
|
||||||
@@ -507,6 +519,8 @@ public static class LegacyMimCatalogImporter
|
|||||||
Emotion,
|
Emotion,
|
||||||
FunFacts,
|
FunFacts,
|
||||||
FavoriteAnimal,
|
FavoriteAnimal,
|
||||||
|
Friend,
|
||||||
|
BestFriend,
|
||||||
Sing,
|
Sing,
|
||||||
HolidaySing,
|
HolidaySing,
|
||||||
FunFactSource,
|
FunFactSource,
|
||||||
@@ -568,6 +582,8 @@ public static class LegacyMimCatalogImporter
|
|||||||
private readonly List<JiboConditionedReply> _emotionReplies = [];
|
private readonly List<JiboConditionedReply> _emotionReplies = [];
|
||||||
private readonly List<string> _fallbacks = [];
|
private readonly List<string> _fallbacks = [];
|
||||||
private readonly List<string> _favoriteAnimalReplies = [];
|
private readonly List<string> _favoriteAnimalReplies = [];
|
||||||
|
private readonly List<string> _friendReplies = [];
|
||||||
|
private readonly List<string> _bestFriendReplies = [];
|
||||||
private readonly List<string> _funFacts = [];
|
private readonly List<string> _funFacts = [];
|
||||||
private readonly List<string> _greetings = [];
|
private readonly List<string> _greetings = [];
|
||||||
private readonly List<string> _holidayGiftReplies = [];
|
private readonly List<string> _holidayGiftReplies = [];
|
||||||
@@ -690,6 +706,12 @@ public static class LegacyMimCatalogImporter
|
|||||||
case LegacyMimBucket.FavoriteAnimal:
|
case LegacyMimBucket.FavoriteAnimal:
|
||||||
AddDistinct(_favoriteAnimalReplies, text);
|
AddDistinct(_favoriteAnimalReplies, text);
|
||||||
return;
|
return;
|
||||||
|
case LegacyMimBucket.Friend:
|
||||||
|
AddDistinct(_friendReplies, text);
|
||||||
|
return;
|
||||||
|
case LegacyMimBucket.BestFriend:
|
||||||
|
AddDistinct(_bestFriendReplies, text);
|
||||||
|
return;
|
||||||
case LegacyMimBucket.PersonalReportKickOff:
|
case LegacyMimBucket.PersonalReportKickOff:
|
||||||
AddDistinct(_personalReportKickOffReplies, text);
|
AddDistinct(_personalReportKickOffReplies, text);
|
||||||
return;
|
return;
|
||||||
@@ -794,6 +816,8 @@ public static class LegacyMimCatalogImporter
|
|||||||
HumanFacts = [.. _humanFacts],
|
HumanFacts = [.. _humanFacts],
|
||||||
FunFacts = [.. _funFacts],
|
FunFacts = [.. _funFacts],
|
||||||
FavoriteAnimalReplies = [.. _favoriteAnimalReplies],
|
FavoriteAnimalReplies = [.. _favoriteAnimalReplies],
|
||||||
|
FriendReplies = [.. _friendReplies],
|
||||||
|
BestFriendReplies = [.. _bestFriendReplies],
|
||||||
SingReplies = [.. _singReplies],
|
SingReplies = [.. _singReplies],
|
||||||
HolidaySingReplies = [.. _holidaySingReplies],
|
HolidaySingReplies = [.. _holidaySingReplies],
|
||||||
GreetingReplies = [.. _greetings],
|
GreetingReplies = [.. _greetings],
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ Holiday-specific note:
|
|||||||
- `RN_HappyBirthdayToJibo` now lands in the birthday celebration bucket
|
- `RN_HappyBirthdayToJibo` now lands in the birthday celebration bucket
|
||||||
- birthday memory authoring now also writes loop-scoped custom holiday records so personal dates can join the holiday list later
|
- birthday memory authoring now also writes loop-scoped custom holiday records so personal dates can join the holiday list later
|
||||||
The newest social batch adds `welcome back`, `what are you thinking`, `what have you been doing`, and `what did you do` responses so the presence and charm lane keeps growing alongside seasonal content.
|
The newest social batch adds `welcome back`, `what are you thinking`, `what have you been doing`, and `what did you do` responses so the presence and charm lane keeps growing alongside seasonal content.
|
||||||
|
The friendship batch adds `RI_JBO_HasFriends`, `RI_JBO_IsFriendsWithUser`, `RI_JBO_IsFriendsWithLM`, `RI_JBO_IsFriendsWithNonLM`, `RI_JBO_IsFriendsWithToaster`, and `RI_JBO_IsBestFriendsWithUser` so the friend and best-friend questions stay source-backed too.
|
||||||
The fun-fact and joke batch adds Pegasus-style `TellAJoke`, `TellRobotFact`, and `Shuffle` excerpts so proactive fun can randomize across more than one category.
|
The fun-fact and joke batch adds Pegasus-style `TellAJoke`, `TellRobotFact`, and `Shuffle` excerpts so proactive fun can randomize across more than one category.
|
||||||
Those facts are now split into generic, robot, and human buckets so the randomizer can sound more like Pegasus while staying lightweight.
|
Those facts are now split into generic, robot, and human buckets so the randomizer can sound more like Pegasus while staying lightweight.
|
||||||
The new favorites batch adds longer authored `favorite color`, `favorite food`, and `favorite music` variants so the familiar personality responses keep more of the original cadence instead of collapsing to short placeholders.
|
The new favorites batch adds longer authored `favorite color`, `favorite food`, and `favorite music` variants so the familiar personality responses keep more of the original cadence instead of collapsing to short placeholders.
|
||||||
|
|||||||
@@ -186,6 +186,33 @@ public sealed class LegacyMimCatalogImporterTests
|
|||||||
reply.Contains("north Pole", StringComparison.OrdinalIgnoreCase));
|
reply.Contains("north Pole", StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ImportCatalog_ImportsBuildBFriendshipResponsesIntoFriendBuckets()
|
||||||
|
{
|
||||||
|
var rootDirectory = Path.Combine(
|
||||||
|
AppContext.BaseDirectory,
|
||||||
|
"Content",
|
||||||
|
"LegacyMims",
|
||||||
|
"BuildB");
|
||||||
|
|
||||||
|
var catalog = LegacyMimCatalogImporter.ImportCatalog(rootDirectory);
|
||||||
|
|
||||||
|
Assert.Contains(catalog.FriendReplies, reply =>
|
||||||
|
reply.Contains("always up for more", StringComparison.OrdinalIgnoreCase));
|
||||||
|
Assert.Contains(catalog.FriendReplies, reply =>
|
||||||
|
reply.Contains("robot kind of way", StringComparison.OrdinalIgnoreCase));
|
||||||
|
Assert.Contains(catalog.FriendReplies, reply =>
|
||||||
|
reply.Contains("making new friends", StringComparison.OrdinalIgnoreCase));
|
||||||
|
Assert.Contains(catalog.FriendReplies, reply =>
|
||||||
|
reply.Contains("don't know if we've met yet", StringComparison.OrdinalIgnoreCase));
|
||||||
|
Assert.Contains(catalog.FriendReplies, reply =>
|
||||||
|
reply.Contains("don't know what I'd do without you", StringComparison.OrdinalIgnoreCase));
|
||||||
|
Assert.Contains("I'd have to say I'm best friends with anyone in my Loop.",
|
||||||
|
catalog.BestFriendReplies);
|
||||||
|
Assert.Contains(catalog.BestFriendReplies, reply =>
|
||||||
|
reply.Contains("You are", StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ImportCatalog_ImportsBuildBEmotionResponsesIntoEmotionBucket()
|
public void ImportCatalog_ImportsBuildBEmotionResponsesIntoEmotionBucket()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -475,6 +475,9 @@ public sealed class JiboInteractionServiceTests
|
|||||||
[InlineData("do you like kids", "robot_likes_kids", "kids are so fun")]
|
[InlineData("do you like kids", "robot_likes_kids", "kids are so fun")]
|
||||||
[InlineData("can you laugh", "robot_can_laugh", "when I'm happy")]
|
[InlineData("can you laugh", "robot_can_laugh", "when I'm happy")]
|
||||||
[InlineData("can you dance", "robot_can_dance", "dancing is one of the things I know best")]
|
[InlineData("can you dance", "robot_can_dance", "dancing is one of the things I know best")]
|
||||||
|
[InlineData("do you have friends", "robot_has_friends", "I believe I do have friends")]
|
||||||
|
[InlineData("are we friends", "robot_is_friends_with_user", "don't know what I'd do without you")]
|
||||||
|
[InlineData("are we best friends", "robot_best_friends", "best friends with anyone in my Loop")]
|
||||||
[InlineData("can you sing", "robot_can_sing", "sing")]
|
[InlineData("can you sing", "robot_can_sing", "sing")]
|
||||||
[InlineData("will you sing", "robot_can_sing", "sing")]
|
[InlineData("will you sing", "robot_can_sing", "sing")]
|
||||||
[InlineData("can you sing a christmas song", "robot_sing_christmas_song", "sing")]
|
[InlineData("can you sing a christmas song", "robot_sing_christmas_song", "sing")]
|
||||||
|
|||||||
Reference in New Issue
Block a user