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
*.RestApi.xml
/BotSharp.WebHost/App_Data/AgentStorage
/BotSharp.WebHost/App_Data/SessionStorage

View file

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

View file

@ -16,9 +16,6 @@ namespace BotSharp.Core.AgentStorage
public class AgentStorageInFile<TAgent> : IAgentStorage<TAgent>
where TAgent : AgentBase
{
private static CSRedisClient csredis;
private static string prefix = String.Empty;
private static string storageDir;
public AgentStorageInFile()
@ -27,7 +24,7 @@ namespace BotSharp.Core.AgentStorage
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);
storageDir = storageDir.Replace("|DataDirectory|", contentDir + Path.DirectorySeparatorChar + "AgentStorage" + Path.DirectorySeparatorChar);
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 Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
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.settings = settings;
GetAgentStorage();
}
public async Task<List<TAgent>> GetAllAgents()
{
await GetStorage();
return await Storage.Query();
}
@ -80,15 +79,11 @@ namespace BotSharp.Core
public async Task<TAgent> GetAgentById(string agentId)
{
GetStorage();
return await Storage.FetchById(agentId);
}
public async Task<TAgent> GetAgentByName(string agentName)
{
await GetStorage();
return await Storage.FetchByName(agentName);
}
@ -195,7 +190,7 @@ namespace BotSharp.Core
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)
@ -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();
}
public virtual async Task<bool> SaveAgent(TAgent agent)
{
await GetStorage();
// default save agent in FileStorage
await Storage.Persist(agent);
return true;
}
protected async Task<IAgentStorage<TAgent>> GetStorage()
protected IAgentStorage<TAgent> GetAgentStorage()
{
if (Storage == null)
{
Storage = await agentStorageFactory.Get();
Storage = agentStorageFactory.Get();
}
return Storage;
}
}

View file

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

View file

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

View file

@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
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> AssembleResult<TResult>(AiResponse response);
Task<TResult> AssembleResult<TResult>(AiRequest request, AiResponse response);
Task<TextClassificationResult> FallbackResponse(AiRequest request);
}

View file

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

View file

@ -24,11 +24,13 @@ namespace BotSharp.Platform.Dialogflow
where TAgent : AgentModel
{
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)
{
this.config = config;
this.contextStorageFactory = contextStorageFactory;
}
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 presetResponse = intent.Responses.FirstOrDefault();
@ -135,7 +137,7 @@ namespace BotSharp.Platform.Dialogflow
var matches = Regex.Matches(presetResponse.Messages.Random().Speech, "\".*?\"").Cast<Match>();
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
{
@ -160,7 +162,7 @@ namespace BotSharp.Platform.Dialogflow
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
{
@ -170,6 +172,8 @@ namespace BotSharp.Platform.Dialogflow
}).ToList();
// persist
var ctxStore = contextStorageFactory.Get();
ctxStore.Persist(sessionId, newContexts.ToArray());
return newContexts;
}

View file

@ -1,5 +1,6 @@
using BotSharp.Core;
using BotSharp.Core.AgentStorage;
using BotSharp.Core.ContextStorage;
using BotSharp.Core.Modules;
using BotSharp.Platform.Abstraction;
using BotSharp.Platform.Dialogflow.Models;
@ -21,6 +22,7 @@ namespace BotSharp.Platform.Dialogflow
services.AddSingleton<DialogflowAi<AgentModel>>();
AgentStorageServiceRegister.Register<AgentModel>(services);
PlatformConfigServiceRegister.Register<PlatformSettings>("dialogflowAi", services, config);
ContextStorageServiceRegister.Register<AIContext>(services);
}
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.
"dialogflowAi": {
"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_",
"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",
"File": "|DataDirectory|AgentStorage"
"File": "|DataDirectory|"
}
}
}