Add RichType to IRichMessage

This commit is contained in:
Haiping Chen 2023-12-18 16:38:12 -06:00
parent d7bba4522a
commit 8cc1094469
20 changed files with 190 additions and 104 deletions

View file

@ -0,0 +1,6 @@
namespace BotSharp.Abstraction.Messaging;
public interface IRichContentService
{
List<IRichMessage> ConvertToMessages(string content);
}

View file

@ -3,4 +3,5 @@ namespace BotSharp.Abstraction.Messaging;
public interface IRichMessage
{
string Text { get; set; }
string RichType => "text";
}

View file

@ -1,15 +1,14 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
namespace BotSharp.Abstraction.Messaging.Models.RichContent
public class QuickReplyElement
{
public class QuickReplyElement
{
[JsonPropertyName("content_type")]
public string ContentType { get; set; } = "text";
[JsonPropertyName("content_type")]
public string ContentType { get; set; } = "text";
public string Title { get; set; } = string.Empty;
public string? Payload { get; set; }
public string Title { get; set; } = string.Empty;
public string? Payload { get; set; }
[JsonPropertyName("image_url")]
public string? ImageUrl { get; set; }
}
[JsonPropertyName("image_url")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ImageUrl { get; set; }
}

View file

@ -1,10 +1,11 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent
{
public class QuickReplyMessage : IRichMessage
{
public string Text { get; set; } = string.Empty;
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
[JsonPropertyName("quick_replies")]
public List<QuickReplyElement> QuickReplies { get; set; } = new List<QuickReplyElement>();
}
public class QuickReplyMessage : IRichMessage
{
[JsonPropertyName("rich_type")]
public string RichType => "quick_reply";
public string Text { get; set; } = string.Empty;
[JsonPropertyName("quick_replies")]
public List<QuickReplyElement> QuickReplies { get; set; } = new List<QuickReplyElement>();
}

View file

@ -1,8 +1,6 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
namespace BotSharp.Abstraction.Messaging.Models.RichContent
public class Recipient
{
public class Recipient
{
public string Id { get; set; } = string.Empty;
}
public string Id { get; set; } = string.Empty;
}

View file

@ -1,13 +1,12 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
public class RichContent<T> where T : IRichMessage
{
public class RichContent<T> where T : IRichMessage
{
public Recipient Recipient { get; set; } = new Recipient();
/// <summary>
/// RESPONSE
/// </summary>
[JsonPropertyName("messaging_type")]
public string MessagingType => "RESPONSE";
public T Message { get; set; }
}
public Recipient Recipient { get; set; } = new Recipient();
/// <summary>
/// RESPONSE
/// </summary>
[JsonPropertyName("messaging_type")]
public string MessagingType => "RESPONSE";
public T Message { get; set; }
}

View file

@ -1,15 +1,13 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent;
namespace BotSharp.Abstraction.Messaging.Models.RichContent
public class SenderActionMessage
{
public class SenderActionMessage
{
/*
* Requests to display sender action should only include the sender_action parameter and the recipient object.
* All other Send API properties, such as text and templates, should be sent in a separate request.
*/
public Recipient Recipient { get; set; } = new Recipient();
/*
* Requests to display sender action should only include the sender_action parameter and the recipient object.
* All other Send API properties, such as text and templates, should be sent in a separate request.
*/
public Recipient Recipient { get; set; } = new Recipient();
[JsonPropertyName("sender_action")]
public string SenderAction { get; set; } = string.Empty;
}
[JsonPropertyName("sender_action")]
public string SenderAction { get; set; } = string.Empty;
}

View file

@ -1,30 +1,35 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
/// <summary>
/// https://developers.facebook.com/docs/messenger-platform/send-messages/buttons
/// </summary>
public class ButtonTemplateMessage : IRichMessage, ITemplateMessage
{
[JsonPropertyName("rich_type")]
public string RichType => "button_template";
[JsonPropertyName("text")]
public string Text { get; set; } = string.Empty;
[JsonPropertyName("template_type")]
public string TemplateType => "button";
[JsonPropertyName("buttons")]
public ButtonElement[] Buttons { get; set; } = new ButtonElement[0];
}
public class ButtonElement
{
/// <summary>
/// https://developers.facebook.com/docs/messenger-platform/send-messages/buttons
/// web_url, postback, phone_number
/// </summary>
public class ButtonTemplateMessage : IRichMessage
{
public string Text { get; set; } = string.Empty;
public string Type { get; set; } = "web_url";
[JsonPropertyName("template_type")]
public string TemplateType => "button";
public List<ButtonElement> Buttons { get; set; } = new List<ButtonElement>();
}
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Url { get; set; }
public class ButtonElement
{
/// <summary>
/// web_url, postback, phone_number
/// </summary>
public string Type { get; set; } = "web_url";
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Payload { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Url { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Payload { get; set; }
public string Title { get; set; } = string.Empty;
}
public string Title { get; set; } = string.Empty;
}

View file

@ -6,6 +6,8 @@ namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
/// </summary>
public class CouponTemplateMessage : IRichMessage, ITemplateMessage
{
[JsonPropertyName("rich_type")]
public string RichType => "coupon_template";
[JsonIgnore]
public string Text { get; set; }
public string Title { get; set; }

View file

@ -1,9 +1,15 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
public class GenericTemplateMessage : TemplateMessageBase<GenericElement>, IRichMessage, ITemplateMessage
public class GenericTemplateMessage : IRichMessage, ITemplateMessage
{
[JsonPropertyName("rich_type")]
public string RichType => "generic_template";
[JsonIgnore]
public string Text { get; set; } = string.Empty;
[JsonPropertyName("template_type")]
public override string TemplateType => "generic";
public string TemplateType => "generic";
}
public class GenericElement

View file

@ -1,18 +1,20 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
public class MultiSelectTemplateMessage : IRichMessage, ITemplateMessage
{
public class MultiSelectTemplateMessage : IRichMessage
{
public string Text { get; set; } = string.Empty;
[JsonPropertyName("rich_type")]
public string RichType => "multi-select_template";
[JsonPropertyName("template_type")]
public string TemplateType => "multi-select";
public List<OptionElement> Options { get; set; } = new List<OptionElement>();
}
public string Text { get; set; } = string.Empty;
public class OptionElement
{
public string Title { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public string? Payload { get; set; }
}
[JsonPropertyName("template_type")]
public string TemplateType => "multi-select";
public List<OptionElement> Options { get; set; } = new List<OptionElement>();
}
public class OptionElement
{
public string Title { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public string? Payload { get; set; }
}

View file

@ -1,9 +1,15 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template;
public class ProductTemplateMessage : TemplateMessageBase<ProductElement>, IRichMessage
public class ProductTemplateMessage : IRichMessage, ITemplateMessage
{
[JsonPropertyName("rich_type")]
public string RichType => "generic_template";
[JsonIgnore]
public string Text { get; set; } = string.Empty;
[JsonPropertyName("template_type")]
public override string TemplateType => "product";
public string TemplateType => "product";
}
public class ProductElement

View file

@ -1,12 +0,0 @@
namespace BotSharp.Abstraction.Messaging.Models.RichContent.Template
{
public class TemplateMessageBase<T>
{
[JsonIgnore]
public string Text { get; set; }
[JsonPropertyName("template_type")]
public virtual string TemplateType => string.Empty;
public T[] Elements { get; set; }
}
}

View file

@ -2,6 +2,9 @@ namespace BotSharp.Abstraction.Messaging.Models.RichContent;
public class TextMessage : IRichMessage
{
[JsonPropertyName("rich_type")]
public string RichType => "text";
public string Text { get; set; } = string.Empty;
public TextMessage(string text)

View file

@ -20,7 +20,8 @@ using BotSharp.Abstraction.MLTasks.Settings;
using BotSharp.Abstraction.Planning;
using BotSharp.Core.Planning;
using BotSharp.Abstraction.MLTasks;
using static Dapper.SqlMapper;
using BotSharp.Abstraction.Messaging;
using BotSharp.Core.Messaging;
namespace BotSharp.Core;
@ -98,6 +99,9 @@ public static class BotSharpCoreExtensions
services.AddScoped<IAgentHook, RoutingAgentHook>();
// Rich content messaging
services.AddScoped<IRichContentService, RichContentService>();
// Evaluation
var evalSetting = new EvaluatorSetting();
config.Bind("Evaluator", evalSetting);

View file

@ -0,0 +1,37 @@
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Messaging.Models.RichContent;
namespace BotSharp.Core.Messaging;
public class RichContentService : IRichContentService
{
public List<IRichMessage> ConvertToMessages(string content)
{
var messages = new List<IRichMessage>();
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
var tempMessages = JsonSerializer.Deserialize<JsonDocument[]>(content, options);
foreach (var m in tempMessages)
{
var richType = "text";
if (m.RootElement.TryGetProperty("rich_type", out var element))
{
richType = element.GetString();
}
if (richType == "text")
{
messages.Add(JsonSerializer.Deserialize<TextMessage>(m.RootElement.ToString(), options));
}
else if (richType == "quick_reply")
{
messages.Add(JsonSerializer.Deserialize<QuickReplyMessage>(m.RootElement.ToString(), options));
}
}
return messages.ToList();
}
}

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Messaging.Models.RichContent;
using Microsoft.AspNetCore.SignalR;
@ -27,10 +28,8 @@ public class ChatHubConversationHook : ConversationHookBase
var welcomeTemplate = agent.Templates.FirstOrDefault(x => x.Name == "welcome");
if (welcomeTemplate != null)
{
var messages = JsonSerializer.Deserialize<TextMessage[]>(welcomeTemplate.Content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
var richContentService = _services.GetRequiredService<IRichContentService>();
var messages = richContentService.ConvertToMessages(welcomeTemplate.Content);
foreach (var message in messages)
{

View file

@ -5,6 +5,9 @@ namespace BotSharp.Plugin.MetaMessenger.MessagingModels;
/// </summary>
public class AttachmentMessage : IRichMessage
{
[JsonPropertyName("rich_type")]
public string RichType => "attachment";
[JsonIgnore]
public string Text { get; set; }

View file

@ -0,0 +1,24 @@
using System.Text.Json.Serialization.Metadata;
namespace BotSharp.Plugin.MetaMessenger.Services;
public static class ConditionalSerialization
{
/// <summary>
/// https://devblogs.microsoft.com/dotnet/system-text-json-in-dotnet-7/#example-conditional-serialization
/// </summary>
/// <param name="typeInfo"></param>
public static void IgnoreRichType(JsonTypeInfo typeInfo)
{
if (typeInfo.Type.GetInterface(nameof(IRichMessage)) == null)
return;
foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
{
if (propertyInfo.Name == "rich_type")
{
propertyInfo.ShouldSerialize = static (obj, value) => false;
}
}
}
}

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Conversations.Enums;
using BotSharp.Abstraction.Messaging.Models.RichContent;
using BotSharp.Abstraction.Utilities;
using System.Text.Json.Serialization.Metadata;
namespace BotSharp.Plugin.MetaMessenger.Services;
@ -19,7 +20,11 @@ public class MessageHandleService
Converters =
{
new RichContentJsonConverter(),
new TemplateMessageJsonConverter()
new TemplateMessageJsonConverter(),
},
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers = { ConditionalSerialization.IgnoreRichType }
}
};
}