feat: add WeChat Plugin

This commit is contained in:
xbotter 2023-06-24 17:25:55 +08:00
parent e3c9d0632c
commit 2e271e1de7
No known key found for this signature in database
GPG key ID: D299220A7FE5CF1E
7 changed files with 206 additions and 2 deletions

View file

@ -20,7 +20,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Senparc.Weixin.MP.MVC" Version="7.12.5.7" />
<ProjectReference Include="..\..\Infrastructure\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Senparc.Weixin.MP.MVC" Version="7.12.7" />
<PackageReference Include="System.Threading.Channels" Version="7.0.0" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,50 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
using BotSharp.Abstraction.Models;
using Microsoft.Extensions.DependencyInjection;
using Senparc.NeuChar.App.AppStore;
using Senparc.NeuChar.Entities;
using Senparc.Weixin.MP.Entities;
using Senparc.Weixin.MP.Entities.Request;
using Senparc.Weixin.MP.MessageContexts;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace BotSharp.Plugin.WeChat
{
public class BotSharpMessageHandler : Senparc.Weixin.MP.MessageHandlers.MessageHandler<DefaultMpMessageContext>
{
public BotSharpMessageHandler(Stream inputStream, PostModel postModel, int maxRecordCount = 0, bool onlyAllowEncryptMessage = false, DeveloperInfo developerInfo = null, IServiceProvider serviceProvider = null) : base(inputStream, postModel, maxRecordCount, onlyAllowEncryptMessage, developerInfo, serviceProvider)
{
}
public BotSharpMessageHandler(XDocument requestDocument, PostModel postModel, int maxRecordCount = 0, bool onlyAllowEncryptMessage = false, DeveloperInfo developerInfo = null, IServiceProvider serviceProvider = null) : base(requestDocument, postModel, maxRecordCount, onlyAllowEncryptMessage, developerInfo, serviceProvider)
{
}
public BotSharpMessageHandler(RequestMessageBase requestMessageBase, PostModel postModel, int maxRecordCount = 0, bool onlyAllowEncryptMessage = false, DeveloperInfo developerInfo = null, IServiceProvider serviceProvider = null) : base(requestMessageBase, postModel, maxRecordCount, onlyAllowEncryptMessage, developerInfo, serviceProvider)
{
}
public override IResponseMessageBase DefaultResponseMessage(IRequestMessageBase requestMessage)
{
return null;
}
public async override Task<IResponseMessageBase> OnTextRequestAsync(RequestMessageText requestMessage)
{
var messageQueue = ServiceProvider.GetRequiredService<IMessageQueue>();
await messageQueue.EnqueueAsync(new WeChatMessage()
{
OpenId = OpenId,
Message = requestMessage.Content,
Type = "text"
});
return await base.OnTextRequestAsync(requestMessage);
}
}
}

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace BotSharp.Plugin.WeChat
{
public interface IMessageQueue
{
Task EnqueueAsync(WeChatMessage message);
}
}

View file

@ -0,0 +1,90 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Infrastructures.ContentTransmitters;
using BotSharp.Abstraction.Models;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
namespace BotSharp.Plugin.WeChat
{
public class WeChatBackgroundService : IHostedService, IMessageQueue
{
private readonly Channel<WeChatMessage> _queue;
private readonly IConversationService _conversationService;
private readonly IContentTransfer _contentTransfer;
private readonly ILogger<WeChatBackgroundService> _logger;
public WeChatBackgroundService(IConversationService conversationService,
IContentTransfer contentTransfer,
ILogger<WeChatBackgroundService> logger)
{
this._conversationService = conversationService;
this._contentTransfer = contentTransfer;
this._logger = logger;
this._queue = Channel.CreateUnbounded<WeChatMessage>();
}
private async Task HandleTextMessageAsync(string openid, string message)
{
var conversations = _conversationService.GetDialogHistory(openid);
conversations.Add(new RoleDialogModel
{
Role = "User",
Text = message,
});
var container = new ContentContainer
{
Conversations = conversations
};
var result = await _contentTransfer.Transport(container);
if (result.IsSuccess)
{
var output = container.Output.Text.Trim();
await ReplyTextMessageAsync(openid, output);
_conversationService.AddDialog(new RoleDialogModel()
{
Role = "Assistant",
Text = output,
});
}
}
private async Task ReplyTextMessageAsync(string openid, string content)
{
var appId = Senparc.Weixin.Config.SenparcWeixinSetting.WeixinAppId;
await Senparc.Weixin.MP.AdvancedAPIs.CustomApi.SendTextAsync(appId, openid, content);
}
public async Task StartAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
var message = await _queue.Reader.ReadAsync(cancellationToken);
await HandleTextMessageAsync(message.OpenId, message.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred Handle Message");
}
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public async Task EnqueueAsync(WeChatMessage message)
{
await _queue.Writer.WriteAsync(message);
}
}
}

View file

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BotSharp.Plugin.WeChat
{
public class WeChatMessage
{
public string OpenId { get; set; }
public string Type { get; set; }
public string Message { get; set; }
}
}

View file

@ -0,0 +1,34 @@
using BotSharp.Abstraction.Plugins;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Senparc.Weixin.AspNet;
using Senparc.Weixin.RegisterServices;
using System;
using System.Collections.Generic;
using System.Text;
namespace BotSharp.Plugin.WeChat
{
public class WeChatPlugin : IBotSharpPlugin
{
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
services.AddMemoryCache();
services.AddSenparcWeixinServices(config);
services.AddHostedService<WeChatBackgroundService>();
services.TryAddSingleton<IMessageQueue>(s => s.GetRequiredService<WeChatBackgroundService>());
}
public void ConfigurateApplication(IApplicationBuilder app)
{
// TODO: app.UseSenparcWeixin
}
}
}

View file

@ -48,7 +48,7 @@
"Master": "mongodb://localhost:27017/chat-ui"
},
"Agent": {
"Master": "Data Source=(localdb)\\ProjectModels;Initial Catalog=Agent;Integrated Security=True;Connect Timeout=30;Encrypt=False;Trust Server Certificate=False;Application Intent=ReadWrite;Multi Subnet Failover=False",
"Master": "Data Source=(localdb)\\mssqllocaldb;Initial Catalog=Agent;Integrated Security=True;Connect Timeout=30;Encrypt=False;Trust Server Certificate=False;Application Intent=ReadWrite;Multi Subnet Failover=False",
"Slavers": []
},
"UseCamelCase": true,