add ContextStorageFactory

persist context to file
This commit is contained in:
haiping008 2018-12-07 16:57:26 -06:00
parent 0520eddc6e
commit 3c7c3c183b
17 changed files with 146 additions and 28 deletions

1
.gitignore vendored
View file

@ -291,3 +291,4 @@ __pycache__/
/docs/_build /docs/_build
*.RestApi.xml *.RestApi.xml
/BotSharp.WebHost/App_Data/AgentStorage /BotSharp.WebHost/App_Data/AgentStorage
/BotSharp.WebHost/App_Data/SessionStorage

View file

@ -19,7 +19,7 @@ namespace BotSharp.Core.AgentStorage
this.platformSetting = setting; this.platformSetting = setting;
} }
public async Task<IAgentStorage<TAgent>> Get() public IAgentStorage<TAgent> Get()
{ {
IAgentStorage<TAgent> storage = null; IAgentStorage<TAgent> storage = null;
string storageName = this.platformSetting.AgentStorage; string storageName = this.platformSetting.AgentStorage;

View file

@ -16,9 +16,6 @@ namespace BotSharp.Core.AgentStorage
public class AgentStorageInFile<TAgent> : IAgentStorage<TAgent> public class AgentStorageInFile<TAgent> : IAgentStorage<TAgent>
where TAgent : AgentBase where TAgent : AgentBase
{ {
private static CSRedisClient csredis;
private static string prefix = String.Empty;
private static string storageDir; private static string storageDir;
public AgentStorageInFile() public AgentStorageInFile()
@ -27,7 +24,7 @@ namespace BotSharp.Core.AgentStorage
var db = config.GetSection("Database:Default").Value; var db = config.GetSection("Database:Default").Value;
storageDir = config.GetSection($"Database:ConnectionStrings:{db}").Value; storageDir = config.GetSection($"Database:ConnectionStrings:{db}").Value;
string contentDir = AppDomain.CurrentDomain.GetData("DataPath").ToString(); string contentDir = AppDomain.CurrentDomain.GetData("DataPath").ToString();
storageDir = storageDir.Replace("|DataDirectory|", contentDir + Path.DirectorySeparatorChar); storageDir = storageDir.Replace("|DataDirectory|", contentDir + Path.DirectorySeparatorChar + "AgentStorage" + Path.DirectorySeparatorChar);
if (!Directory.Exists(storageDir)) if (!Directory.Exists(storageDir))
{ {

View file

@ -0,0 +1,28 @@
using BotSharp.Platform.Abstraction;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace BotSharp.Core.ContextStorage
{
public class ContextStorageFactory<T> : IContextStorageFactory<T>
{
private readonly Func<string, IContextStorage<T>> func;
private readonly IPlatformSettings platformSetting;
public ContextStorageFactory(IPlatformSettings setting, Func<string, IContextStorage<T>> serviceAccessor)
{
this.func = serviceAccessor;
this.platformSetting = setting;
}
public IContextStorage<T> Get()
{
IContextStorage<T> storage = null;
string storageName = this.platformSetting.ContextStorage;
storage = func(storageName);
return storage as IContextStorage<T>;
}
}
}

View file

@ -1,12 +1,51 @@
using BotSharp.Platform.Abstraction; using BotSharp.Platform.Abstraction;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace BotSharp.Core.ContextStorage namespace BotSharp.Core.ContextStorage
{ {
public class ContextStorageInFile : IContextStorage public class ContextStorageInFile<T> : IContextStorage<T>
{ {
private static string storageDir;
public ContextStorageInFile()
{
IConfiguration config = (IConfiguration)AppDomain.CurrentDomain.GetData("Configuration");
var db = config.GetSection("Database:Default").Value;
storageDir = config.GetSection($"Database:ConnectionStrings:{db}").Value;
string contentDir = AppDomain.CurrentDomain.GetData("DataPath").ToString();
storageDir = storageDir.Replace("|DataDirectory|", contentDir + Path.DirectorySeparatorChar + "SessionStorage" + Path.DirectorySeparatorChar);
if (!Directory.Exists(storageDir))
{
Directory.CreateDirectory(storageDir);
}
}
public async Task<bool> Persist(string sessionId, T[] context)
{
var json = JsonConvert.SerializeObject(context, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
Formatting = Formatting.Indented,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters = new List<JsonConverter>
{
new Newtonsoft.Json.Converters.StringEnumConverter()
}
});
string dataPath = Path.Combine(storageDir, sessionId + ".json");
File.WriteAllText(dataPath, json);
return true;
}
} }
} }

View file

@ -0,0 +1,35 @@
using BotSharp.Platform.Abstraction;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
namespace BotSharp.Core.ContextStorage
{
public class ContextStorageServiceRegister
{
public static void Register<T>(IServiceCollection services)
{
services.AddSingleton<IContextStorageFactory<T>, ContextStorageFactory<T>>();
services.AddSingleton<ContextStorageInFile<T>>();
services.AddSingleton(factory =>
{
Func<string, IContextStorage<T>> accesor = key =>
{
if (key.Equals("ContextStorageInFile"))
{
return factory.GetService<ContextStorageInFile<T>>();
}
else
{
throw new ArgumentException($"Not Support key : {key}");
}
};
return accesor;
});
}
}
}

View file

@ -32,12 +32,11 @@ namespace BotSharp.Core
{ {
this.agentStorageFactory = agentStorageFactory; this.agentStorageFactory = agentStorageFactory;
this.settings = settings; this.settings = settings;
GetAgentStorage();
} }
public async Task<List<TAgent>> GetAllAgents() public async Task<List<TAgent>> GetAllAgents()
{ {
await GetStorage();
return await Storage.Query(); return await Storage.Query();
} }
@ -80,15 +79,11 @@ namespace BotSharp.Core
public async Task<TAgent> GetAgentById(string agentId) public async Task<TAgent> GetAgentById(string agentId)
{ {
GetStorage();
return await Storage.FetchById(agentId); return await Storage.FetchById(agentId);
} }
public async Task<TAgent> GetAgentByName(string agentName) public async Task<TAgent> GetAgentByName(string agentName)
{ {
await GetStorage();
return await Storage.FetchByName(agentName); return await Storage.FetchByName(agentName);
} }
@ -195,7 +190,7 @@ namespace BotSharp.Core
Console.WriteLine($"TextResponse: {aiResponse.Intent}, {request.SessionId}"); Console.WriteLine($"TextResponse: {aiResponse.Intent}, {request.SessionId}");
return await AssembleResult<TResult>(aiResponse); return await AssembleResult<TResult>(request, aiResponse);
} }
public virtual async Task<TextClassificationResult> FallbackResponse(AiRequest request) public virtual async Task<TextClassificationResult> FallbackResponse(AiRequest request)
@ -222,27 +217,25 @@ namespace BotSharp.Core
} }
} }
public virtual async Task<TResult> AssembleResult<TResult>(AiResponse response) public virtual async Task<TResult> AssembleResult<TResult>(AiRequest request, AiResponse response)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public virtual async Task<bool> SaveAgent(TAgent agent) public virtual async Task<bool> SaveAgent(TAgent agent)
{ {
await GetStorage();
// default save agent in FileStorage // default save agent in FileStorage
await Storage.Persist(agent); await Storage.Persist(agent);
return true; return true;
} }
protected IAgentStorage<TAgent> GetAgentStorage()
protected async Task<IAgentStorage<TAgent>> GetStorage()
{ {
if (Storage == null) if (Storage == null)
{ {
Storage = await agentStorageFactory.Get(); Storage = agentStorageFactory.Get();
} }
return Storage; return Storage;
} }
} }

View file

@ -16,10 +16,13 @@ namespace BotSharp.Core
{ {
BotEngine = "BotSharpNLU"; BotEngine = "BotSharpNLU";
AgentStorage = "AgentStorageInFile"; AgentStorage = "AgentStorageInFile";
ContextStorage = "ContextStorageInFile";
} }
public string BotEngine { get; set; } public string BotEngine { get; set; }
public string ContextStorage { get; set; }
public string AgentStorage { get; set; } public string AgentStorage { get; set; }
} }

View file

@ -6,6 +6,6 @@ namespace BotSharp.Platform.Abstraction
{ {
public interface IAgentStorageFactory<TAgent> where TAgent : AgentBase public interface IAgentStorageFactory<TAgent> where TAgent : AgentBase
{ {
Task<IAgentStorage<TAgent>> Get(); IAgentStorage<TAgent> Get();
} }
} }

View file

@ -1,10 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks;
namespace BotSharp.Platform.Abstraction namespace BotSharp.Platform.Abstraction
{ {
public interface IContextStorage public interface IContextStorage<T>
{ {
Task<bool> Persist(string sessionId, T[] context);
} }
} }

View file

@ -0,0 +1,11 @@
using BotSharp.Platform.Abstraction;
using BotSharp.Platform.Models;
using System.Threading.Tasks;
namespace BotSharp.Platform.Abstraction
{
public interface IContextStorageFactory<T>
{
IContextStorage<T> Get();
}
}

View file

@ -51,7 +51,7 @@ namespace BotSharp.Platform.Abstraction
Task<TResult> TextRequest<TResult>(AiRequest request); Task<TResult> TextRequest<TResult>(AiRequest request);
Task<TResult> AssembleResult<TResult>(AiResponse response); Task<TResult> AssembleResult<TResult>(AiRequest request, AiResponse response);
Task<TextClassificationResult> FallbackResponse(AiRequest request); Task<TextClassificationResult> FallbackResponse(AiRequest request);
} }

View file

@ -9,5 +9,7 @@ namespace BotSharp.Platform.Abstraction
string BotEngine { get; set; } string BotEngine { get; set; }
string AgentStorage { get; set; } string AgentStorage { get; set; }
string ContextStorage { get; set; }
} }
} }

View file

@ -24,11 +24,13 @@ namespace BotSharp.Platform.Dialogflow
where TAgent : AgentModel where TAgent : AgentModel
{ {
IConfiguration config; IConfiguration config;
IContextStorageFactory<AIContext> contextStorageFactory;
public DialogflowAi(IAgentStorageFactory<TAgent> agentStorageFactory, IPlatformSettings settings, IConfiguration config) public DialogflowAi(IAgentStorageFactory<TAgent> agentStorageFactory, IContextStorageFactory<AIContext> contextStorageFactory, IPlatformSettings settings, IConfiguration config)
:base(agentStorageFactory, settings) :base(agentStorageFactory, settings)
{ {
this.config = config; this.config = config;
this.contextStorageFactory = contextStorageFactory;
} }
public async Task<TrainingCorpus> ExtractorCorpus(TAgent agent) public async Task<TrainingCorpus> ExtractorCorpus(TAgent agent)
@ -110,7 +112,7 @@ namespace BotSharp.Platform.Dialogflow
} }
} }
public override async Task<TResult> AssembleResult<TResult>(AiResponse response) public override async Task<TResult> AssembleResult<TResult>(AiRequest request, AiResponse response)
{ {
var intent = Agent.Intents.Find(x => x.Name == response.Intent); var intent = Agent.Intents.Find(x => x.Name == response.Intent);
var presetResponse = intent.Responses.FirstOrDefault(); var presetResponse = intent.Responses.FirstOrDefault();
@ -135,7 +137,7 @@ namespace BotSharp.Platform.Dialogflow
var matches = Regex.Matches(presetResponse.Messages.Random().Speech, "\".*?\"").Cast<Match>(); var matches = Regex.Matches(presetResponse.Messages.Random().Speech, "\".*?\"").Cast<Match>();
var speech = matches.Count() == 0 ? String.Empty : matches.ToList().Random().Value; var speech = matches.Count() == 0 ? String.Empty : matches.ToList().Random().Value;
var contexts = HandleContexts(presetResponse); var contexts = HandleContexts(request.SessionId, presetResponse);
var aiResponse = new AIResponseResult var aiResponse = new AIResponseResult
{ {
@ -160,7 +162,7 @@ namespace BotSharp.Platform.Dialogflow
return (TResult)(object)aiResponse; return (TResult)(object)aiResponse;
} }
private List<AIContext> HandleContexts(IntentResponse response) private List<AIContext> HandleContexts(string sessionId, IntentResponse response)
{ {
var newContexts = response.Contexts.Select(x => new AIContext var newContexts = response.Contexts.Select(x => new AIContext
{ {
@ -170,6 +172,8 @@ namespace BotSharp.Platform.Dialogflow
}).ToList(); }).ToList();
// persist // persist
var ctxStore = contextStorageFactory.Get();
ctxStore.Persist(sessionId, newContexts.ToArray());
return newContexts; return newContexts;
} }

View file

@ -1,5 +1,6 @@
using BotSharp.Core; using BotSharp.Core;
using BotSharp.Core.AgentStorage; using BotSharp.Core.AgentStorage;
using BotSharp.Core.ContextStorage;
using BotSharp.Core.Modules; using BotSharp.Core.Modules;
using BotSharp.Platform.Abstraction; using BotSharp.Platform.Abstraction;
using BotSharp.Platform.Dialogflow.Models; using BotSharp.Platform.Dialogflow.Models;
@ -21,6 +22,7 @@ namespace BotSharp.Platform.Dialogflow
services.AddSingleton<DialogflowAi<AgentModel>>(); services.AddSingleton<DialogflowAi<AgentModel>>();
AgentStorageServiceRegister.Register<AgentModel>(services); AgentStorageServiceRegister.Register<AgentModel>(services);
PlatformConfigServiceRegister.Register<PlatformSettings>("dialogflowAi", services, config); PlatformConfigServiceRegister.Register<PlatformSettings>("dialogflowAi", services, config);
ContextStorageServiceRegister.Register<AIContext>(services);
} }
public void Configure(IApplicationBuilder app, IHostingEnvironment env) public void Configure(IApplicationBuilder app, IHostingEnvironment env)

View file

@ -2,6 +2,7 @@
// if you want to override platform setting, please set corresponding value, otherwise you don't need this section. // if you want to override platform setting, please set corresponding value, otherwise you don't need this section.
"dialogflowAi": { "dialogflowAi": {
"botEngine": "BotSharpNLU", "botEngine": "BotSharpNLU",
"agentStorage": "AgentStorageInFile" "agentStorage": "AgentStorageInFile",
"contextStorage": "ContextStorageInFile"
} }
} }

View file

@ -6,7 +6,7 @@
"Redis": "127.0.0.1:6379,defaultDatabase=BotSharp,poolsize=50,ssl=false,writeBuffer=10240,prefix=agent_", "Redis": "127.0.0.1:6379,defaultDatabase=BotSharp,poolsize=50,ssl=false,writeBuffer=10240,prefix=agent_",
"Sqlite": "Data Source=|DataDirectory|BotSharp.db;", "Sqlite": "Data Source=|DataDirectory|BotSharp.db;",
"SqlServer": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=BotSharp;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", "SqlServer": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=BotSharp;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
"File": "|DataDirectory|AgentStorage" "File": "|DataDirectory|"
} }
} }
} }