diff --git a/BotSharp.Core/Abstractions/IAgentImporter.cs b/BotSharp.Core/Abstractions/IAgentImporter.cs index 584b4e22..e2ea0acf 100644 --- a/BotSharp.Core/Abstractions/IAgentImporter.cs +++ b/BotSharp.Core/Abstractions/IAgentImporter.cs @@ -10,10 +10,10 @@ namespace BotSharp.Core.Engines /// /// Load agent summary /// - /// agent guid or name + /// /// /// - Agent LoadAgent(string agentId, string agentDir); + Agent LoadAgent(AgentImportHeader agentHeader, string agentDir); /// /// Load user customized entity type diff --git a/BotSharp.Core/Abstractions/IBotPlatform.cs b/BotSharp.Core/Abstractions/IBotPlatform.cs index 48275a7a..df6ee8bd 100644 --- a/BotSharp.Core/Abstractions/IBotPlatform.cs +++ b/BotSharp.Core/Abstractions/IBotPlatform.cs @@ -1,4 +1,5 @@ using BotSharp.Core.Models; +using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Text; @@ -8,6 +9,7 @@ namespace BotSharp.Core.Engines public interface IBotPlatform { AIResponse TextRequest(AIRequest request); + void Train(); } } diff --git a/BotSharp.Core/BotSharp.Core.csproj b/BotSharp.Core/BotSharp.Core.csproj index 35f376ef..0d8a8e26 100644 --- a/BotSharp.Core/BotSharp.Core.csproj +++ b/BotSharp.Core/BotSharp.Core.csproj @@ -25,7 +25,7 @@ - TRACE;MODEL_PER_CONTEXTS;NETCOREAPP;NETCOREAPP2_1 + TRACE;DEBUG @@ -43,9 +43,4 @@ - - - - - diff --git a/BotSharp.Core/Engines/AgentImportHeader.cs b/BotSharp.Core/Engines/AgentImportHeader.cs new file mode 100644 index 00000000..b73c7d4c --- /dev/null +++ b/BotSharp.Core/Engines/AgentImportHeader.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Core.Engines +{ + public class AgentImportHeader + { + public String Id { get; set; } + public String Name { get; set; } + public String UserId { get; set; } + public String ClientAccessToken { get; set; } + public String DeveloperAccessToken { get; set; } + } +} diff --git a/BotSharp.Core/Agents/AgentDriver.cs b/BotSharp.Core/Engines/BotEngineBase.cs similarity index 50% rename from BotSharp.Core/Agents/AgentDriver.cs rename to BotSharp.Core/Engines/BotEngineBase.cs index ba48b6a5..73235248 100644 --- a/BotSharp.Core/Agents/AgentDriver.cs +++ b/BotSharp.Core/Engines/BotEngineBase.cs @@ -1,5 +1,4 @@ -using BotSharp.Core.Adapters.Rasa; -using BotSharp.Core.Engines; +using BotSharp.Core.Agents; using BotSharp.Core.Entities; using BotSharp.Core.Intents; using BotSharp.Core.Models; @@ -7,58 +6,90 @@ using EntityFrameworkCore.BootKit; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; -namespace BotSharp.Core.Agents +namespace BotSharp.Core.Engines { - public static class AgentDriver + /// + /// Bot engine/ platform base class + /// + public abstract class BotEngineBase { - public static Agent LoadAgentById(this IBotPlatform engine, Database dc, string agentId) + protected Database dc; + + public AIConfiguration AiConfig { get; set; } + + protected Agent agent { get; set; } + + public String DbInitializerPath { get; private set; } + + public BotEngineBase() { - var clientAccessToken = dc.Table().Find(agentId).ClientAccessToken; - - var config = new AIConfiguration(clientAccessToken, SupportedLanguage.English); - - var rasa = new RasaAi(dc, config); - rasa.agent = rasa.LoadAgent(dc, config); - - return rasa.agent; + dc = new DefaultDataContextLoader().GetDefaultDc(); + DbInitializerPath = $"{Database.ContentRootPath}App_Data{Path.DirectorySeparatorChar}DbInitializer{Path.DirectorySeparatorChar}"; } - public static Agent LoadAgent(this IBotPlatform engine, Database dc, AIConfiguration aiConfig) + /// + /// Load Agent + /// + /// agentId, clientAccessToken, developerAccessToken + /// + public Agent LoadAgent(string id) { - return dc.Table() - .Include(x => x.Intents).ThenInclude(x => x.Contexts) - .Include(x => x.Entities).ThenInclude(x => x.Entries).ThenInclude(x => x.Synonyms) - .Include(x => x.MlConfig) - .FirstOrDefault(x => x.ClientAccessToken == aiConfig.ClientAccessToken || x.DeveloperAccessToken == aiConfig.ClientAccessToken); + if (agent == null) + { + agent = dc.Table() + .Include(x => x.Intents).ThenInclude(x => x.Contexts) + .Include(x => x.Entities).ThenInclude(x => x.Entries).ThenInclude(x => x.Synonyms) + .Include(x => x.MlConfig) + .FirstOrDefault(x => x.Id == id || + x.ClientAccessToken == id || + x.DeveloperAccessToken == id); + } + else + { + return agent; + } + + return agent; } /// /// Restore a agent instance from backup json files /// - /// - /// + /// + /// + /// /// - public static Agent RestoreAgent(this IBotPlatform engine, IAgentImporter importer, String agentId, string dataDir) + public bool RestoreAgent(AgentImportHeader agentHeader) where TAgentImporter : IAgentImporter, new() { - // Load agent summary - var agent = importer.LoadAgent(agentId, dataDir); + var importer = new TAgentImporter(); - // Load user custom entities - importer.LoadCustomEntities(agent, dataDir); + string dataDir = $"{DbInitializerPath}Agents{Path.DirectorySeparatorChar}"; - // Load agent intents - importer.LoadIntents(agent, dataDir); + int row = dc.DbTran(() => { - // Load system buildin entities - importer.LoadBuildinEntities(agent, dataDir); + // Load agent summary + agent = importer.LoadAgent(agentHeader, dataDir); - return agent; + // Load user custom entities + importer.LoadCustomEntities(agent, dataDir); + + // Load agent intents + importer.LoadIntents(agent, dataDir); + + // Load system buildin entities + importer.LoadBuildinEntities(agent, dataDir); + + SaveAgent(); + }); + + return row > 0; } - public static String SaveAgent(this Agent agent, Database dc) + public String SaveAgent() { var existedAgent = dc.Table().FirstOrDefault(x => x.Id == agent.Id || x.Name == agent.Name); if (existedAgent == null) @@ -73,12 +104,12 @@ namespace BotSharp.Core.Agents } } - public static RasaTrainingData GrabCorpus(this Agent agent, Database dc) + public TrainingCorpus GetIntentExpressions() { - var trainingData = new RasaTrainingData + TrainingCorpus corpus = new TrainingCorpus() { - Entities = new List(), - UserSays = new List() + UserSays = new List>(), + Entities = new List() }; var expressParts = new List(); @@ -93,7 +124,7 @@ namespace BotSharp.Core.Agents { intent.UserSays.ForEach(exp => { - var say = new RasaIntentExpression + var say = new TrainingIntentExpression { Intent = intent.Name, Text = String.Join("", exp.Data.OrderBy(x => x.UpdatedTime).Select(x => x.Text)), @@ -107,7 +138,7 @@ namespace BotSharp.Core.Agents { int start = say.Text.IndexOf(x.Text); - var part = new RasaIntentExpressionPart + var part = new TrainingIntentExpressionPart { Value = x.Text, Entity = $"{x.Meta}:{x.Alias}", @@ -115,11 +146,11 @@ namespace BotSharp.Core.Agents End = start + x.Text.Length }; - if (say.Entities == null) say.Entities = new List(); + if (say.Entities == null) say.Entities = new List(); say.Entities.Add(part); // assemble entity synonmus - if (!trainingData.Entities.Any(y => y.EntityType == x.Alias && y.EntityValue == x.Text)) + /*if (!trainingData.Entities.Any(y => y.EntityType == x.Alias && y.EntityValue == x.Text)) { var allSynonyms = (from e in dc.Table() join ee in dc.Table() on e.Id equals ee.EntityId @@ -127,7 +158,7 @@ namespace BotSharp.Core.Agents where e.Name == x.Alias && ee.Value == x.Text & ees.Synonym != x.Text select ees.Synonym).ToList(); - var te = new RasaTraningEntity + var te = new TrainingEntity { EntityType = $"{x.Meta}:{x.Alias}", EntityValue = x.Text, @@ -135,17 +166,17 @@ namespace BotSharp.Core.Agents }; trainingData.Entities.Add(te); - } + }*/ }); - trainingData.UserSays.Add(say); + corpus.UserSays.Add(say); }); }); // remove Default Fallback Intent - trainingData.UserSays = trainingData.UserSays.Where(x => x.Intent != "Default Fallback Intent").ToList(); + corpus.UserSays = corpus.UserSays.Where(x => x.Intent != "Default Fallback Intent").ToList(); - return trainingData; + return corpus; } } } diff --git a/BotSharp.Core/Engines/BotSharp/BotSharpAi.cs b/BotSharp.Core/Engines/BotSharp/BotSharpAi.cs new file mode 100644 index 00000000..da88bf23 --- /dev/null +++ b/BotSharp.Core/Engines/BotSharp/BotSharpAi.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; +using BotSharp.Core.Models; + +namespace BotSharp.Core.Engines.BotSharp +{ + public class BotSharpAi : BotEngineBase, IBotPlatform + { + public AIResponse TextRequest(AIRequest request) + { + throw new NotImplementedException(); + } + + public void Train() + { + throw new NotImplementedException(); + } + } +} diff --git a/BotSharp.Core/Engines/CRFsuite/CRFsuiteEntityRecognizer.cs b/BotSharp.Core/Engines/CRFsuite/CRFsuiteEntityRecognizer.cs index c50cb7c6..54ad91a9 100644 --- a/BotSharp.Core/Engines/CRFsuite/CRFsuiteEntityRecognizer.cs +++ b/BotSharp.Core/Engines/CRFsuite/CRFsuiteEntityRecognizer.cs @@ -18,7 +18,7 @@ namespace BotSharp.Core.Engines.CRFsuite public bool Process(Agent agent, JObject data) { var dc = new DefaultDataContextLoader().GetDefaultDc(); - var corpus = agent.GrabCorpus(dc); + //var corpus = agent.GrabCorpus(dc); // Mock Data List train_sent = new List(); diff --git a/BotSharp.Core/Engines/Dialogflow/AIConfiguration.cs b/BotSharp.Core/Engines/Dialogflow/AIConfiguration.cs index 1d4978b4..77df4aa2 100644 --- a/BotSharp.Core/Engines/Dialogflow/AIConfiguration.cs +++ b/BotSharp.Core/Engines/Dialogflow/AIConfiguration.cs @@ -13,6 +13,8 @@ namespace BotSharp.Core.Models public string ClientAccessToken { get; private set; } + public string AgentId { get; set; } + public SupportedLanguage Language { get; set; } public bool VoiceActivityDetectionEnabled { get; set; } diff --git a/BotSharp.Core/Engines/Dialogflow/AgentImporterInDialogflow.cs b/BotSharp.Core/Engines/Dialogflow/AgentImporterInDialogflow.cs index a43cfc6a..41581cb0 100644 --- a/BotSharp.Core/Engines/Dialogflow/AgentImporterInDialogflow.cs +++ b/BotSharp.Core/Engines/Dialogflow/AgentImporterInDialogflow.cs @@ -22,18 +22,25 @@ namespace BotSharp.Core.Engines /// /// Load agent meta /// - /// + /// /// /// - public Agent LoadAgent(string agentId, string agentDir) + public Agent LoadAgent(AgentImportHeader agentHeader, string agentDir) { // load agent profile - string data = File.ReadAllText($"{agentDir}{Path.DirectorySeparatorChar}Dialogflow{Path.DirectorySeparatorChar}{agentId}{Path.DirectorySeparatorChar}agent.json"); + string data = File.ReadAllText($"{agentDir}{Path.DirectorySeparatorChar}Dialogflow{Path.DirectorySeparatorChar}{agentHeader.Name}{Path.DirectorySeparatorChar}agent.json"); var agent = JsonConvert.DeserializeObject(data); - agent.Id = Guid.NewGuid().ToString(); - agent.Name = agentId; + agent.Name = agentHeader.Name; + agent.Id = agentHeader.Id; var result = agent.ToObject(); + result.ClientAccessToken = agentHeader.ClientAccessToken; + result.DeveloperAccessToken = agentHeader.DeveloperAccessToken; + if(agentHeader.UserId != null) + { + result.UserId = agentHeader.UserId; + } + result.MlConfig = agent.ToObject(); result.MlConfig.MinConfidence = agent.MlMinConfidence; result.MlConfig.AgentId = agent.Id; diff --git a/BotSharp.Core/Engines/Rasa/RasaAi.cs b/BotSharp.Core/Engines/Rasa/RasaAi.cs index 71530e07..0d23c3e8 100644 --- a/BotSharp.Core/Engines/Rasa/RasaAi.cs +++ b/BotSharp.Core/Engines/Rasa/RasaAi.cs @@ -1,4 +1,5 @@ -using BotSharp.Core.Agents; +using BotSharp.Core.Adapters.Rasa; +using BotSharp.Core.Agents; using BotSharp.Core.Entities; using BotSharp.Core.Intents; using BotSharp.Core.Models; @@ -19,39 +20,17 @@ using System.Text; namespace BotSharp.Core.Engines { /// - /// Rasa nlu 0.12.x + /// Rasa nlu >= 0.12 /// - public class RasaAi : IBotPlatform + public class RasaAi : BotEngineBase, IBotPlatform { - public Database dc { get; set; } - public AIConfiguration AiConfig { get; set; } - - public Agent agent { get; set; } - - public RasaAi(Database dc) - { - this.dc = dc; - } - - public RasaAi(Database dc, AIConfiguration aiConfig) - { - this.dc = dc; - - AiConfig = aiConfig; - agent = this.LoadAgent(dc, aiConfig); - aiConfig.DevMode = agent.DeveloperAccessToken == aiConfig.ClientAccessToken; - } - public AIResponse TextRequest(AIRequest request) { AIResponse aiResponse = new AIResponse(); -#if MODEL_PER_CONTEXTS string model = RasaRequestExtension.GetModelPerContexts(agent, AiConfig, request, dc); var result = CallRasa(agent.Id, request.Query.First(), model); -#else - var result = CallRasa(rasa.agent.Id, request.Query.First(), rasa.agent.Id); -#endif + result.Content.Log(); RasaResponse response = result.Data; @@ -119,7 +98,13 @@ namespace BotSharp.Core.Engines public void Train() { - var corpus = agent.GrabCorpus(dc); + var trainingData = new RasaTrainingData + { + Entities = new List(), + UserSays = new List() + }; + + var corpus = GetIntentExpressions(); var client = new RestClient($"{Database.Configuration.GetSection("Rasa:Nlu").Value}"); var contextHashs = corpus.UserSays @@ -146,8 +131,8 @@ namespace BotSharp.Core.Engines var data = new RasaTrainingData { - Entities = entity_synonyms, - UserSays = common_examples + Entities = entity_synonyms.Select(x => x.ToObject()).ToList(), + UserSays = common_examples.Select(x => x.Intent.ToObject()).ToList() }; // meet minimal requirement @@ -231,47 +216,5 @@ namespace BotSharp.Core.Engines }); } - - [Obsolete] - public string TrainWithoutContext() - { - var client = new RestClient($"{Database.Configuration.GetSection("Rasa:Nlu").Value}"); - var rest = new RestRequest("train", Method.POST); - rest.AddQueryParameter("project", agent.Id); - - var corpus = agent.GrabCorpus(dc); - - string json = JsonConvert.SerializeObject(new { rasa_nlu_data = corpus }, - new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver(), - NullValueHandling = NullValueHandling.Ignore - }); - - string trainingConfig = agent.Language == "zh" ? "config_jieba_mitie_sklearn.yml" : "config_spacy.yml"; - string body = File.ReadAllText($"{Database.ContentRootPath}{Path.DirectorySeparatorChar}Settings{Path.DirectorySeparatorChar}{trainingConfig}"); - body = $"{body}\r\ndata: {json}"; - rest.AddParameter("application/x-yml", body, ParameterType.RequestBody); - - var response = client.Execute(rest); - - if (response.IsSuccessful) - { - var result = JObject.Parse(response.Content); - - string modelName = result["info"].Value().Split(": ")[1]; - - return modelName; - } - else - { - var result = JObject.Parse(response.Content); - - Console.WriteLine(result["error"]); - - return String.Empty; - } - } - } } diff --git a/BotSharp.Core/Engines/Rasa/RasaIntentExpression.cs b/BotSharp.Core/Engines/Rasa/RasaIntentExpression.cs index b3dfcd4c..414f0b50 100644 --- a/BotSharp.Core/Engines/Rasa/RasaIntentExpression.cs +++ b/BotSharp.Core/Engines/Rasa/RasaIntentExpression.cs @@ -1,22 +1,13 @@ -using Newtonsoft.Json; +using BotSharp.Core.Engines; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Text; namespace BotSharp.Core.Models { - public class RasaIntentExpression + public class RasaIntentExpression : TrainingIntentExpression { - public RasaIntentExpression() - { - } - public String Text { get; set; } - public String Intent { get; set; } - - [JsonIgnore] - public String ContextHash { get; set; } - - public List Entities { get; set; } } } diff --git a/BotSharp.Core/Engines/Rasa/RasaIntentExpressionPart.cs b/BotSharp.Core/Engines/Rasa/RasaIntentExpressionPart.cs index d4c254c2..4925df0e 100644 --- a/BotSharp.Core/Engines/Rasa/RasaIntentExpressionPart.cs +++ b/BotSharp.Core/Engines/Rasa/RasaIntentExpressionPart.cs @@ -1,14 +1,11 @@ -using System; +using BotSharp.Core.Engines; +using System; using System.Collections.Generic; using System.Text; namespace BotSharp.Core.Models { - public class RasaIntentExpressionPart + public class RasaIntentExpressionPart : TrainingIntentExpressionPart { - public int Start { get; set; } - public int End { get; set; } - public String Value { get; set; } - public String Entity { get; set; } } } diff --git a/BotSharp.Core/Engines/Rasa/RasaTraningEntity.cs b/BotSharp.Core/Engines/Rasa/RasaTraningEntity.cs index 67a38a28..6ac97ebc 100644 --- a/BotSharp.Core/Engines/Rasa/RasaTraningEntity.cs +++ b/BotSharp.Core/Engines/Rasa/RasaTraningEntity.cs @@ -1,18 +1,17 @@ -using Newtonsoft.Json; +using BotSharp.Core.Engines; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Text; namespace BotSharp.Core.Adapters.Rasa { - public class RasaTraningEntity + public sealed class RasaTraningEntity : TrainingEntity { [JsonIgnore] - public String EntityType { get; set; } + public override String EntityType { get; set; } [JsonProperty("value")] - public String EntityValue { get; set; } - - public List Synonyms { get; set; } + public override String EntityValue { get; set; } } } diff --git a/BotSharp.Core/Engines/SpaCy/SpaCyEntityRecognizer.cs b/BotSharp.Core/Engines/SpaCy/SpaCyEntityRecognizer.cs index a1862712..d0338412 100644 --- a/BotSharp.Core/Engines/SpaCy/SpaCyEntityRecognizer.cs +++ b/BotSharp.Core/Engines/SpaCy/SpaCyEntityRecognizer.cs @@ -27,7 +27,7 @@ namespace BotSharp.Core.Engines.SpaCy List trainingData = new List(); var dc = new DefaultDataContextLoader().GetDefaultDc(); - var corpus = agent.GrabCorpus(dc); + /*var corpus = agent.GrabCorpus(dc); corpus.UserSays.ForEach(userSay => { @@ -40,7 +40,7 @@ namespace BotSharp.Core.Engines.SpaCy }); trainingData.Add(new TrainingNode(userSay.Text, entityLabel)); } - }); + });*/ entitiesInTrainingSet = entitiesInTrainingSet.Distinct().ToList(); var client = new RestClient(Configuration.GetSection("SpaCyProvider:Url").Value); var request = new RestRequest("entityrecognizer", Method.POST); diff --git a/BotSharp.Core/Engines/SpaCy/SpaCyTokenizer.cs b/BotSharp.Core/Engines/SpaCy/SpaCyTokenizer.cs index b36e19d1..0fc22991 100644 --- a/BotSharp.Core/Engines/SpaCy/SpaCyTokenizer.cs +++ b/BotSharp.Core/Engines/SpaCy/SpaCyTokenizer.cs @@ -23,14 +23,14 @@ namespace BotSharp.Core.Engines.SpaCy List> tokens = new List>(); Boolean res = true; var dc = new DefaultDataContextLoader().GetDefaultDc(); - var corpus = agent.GrabCorpus(dc); + /*var corpus = ; corpus.UserSays.ForEach(usersay => { request.AddParameter("text", usersay.Text); var response = client.Execute(request); tokens.Add(response.Data.Tokens); res = res && response.IsSuccessful; - }); + });*/ diff --git a/BotSharp.Core/Engines/SpaCy/SpacyFeaturizer.cs b/BotSharp.Core/Engines/SpaCy/SpacyFeaturizer.cs index 1602141f..f456b8a2 100644 --- a/BotSharp.Core/Engines/SpaCy/SpacyFeaturizer.cs +++ b/BotSharp.Core/Engines/SpaCy/SpacyFeaturizer.cs @@ -21,14 +21,14 @@ namespace BotSharp.Core.Engines.SpaCy List> vectors = new List>(); Boolean res = true; var dc = new DefaultDataContextLoader().GetDefaultDc(); - var corpus = agent.GrabCorpus(dc); + /*var corpus = agent.GrabCorpus(dc); corpus.UserSays.ForEach(usersay => { request.AddParameter("text", usersay.Text); var response = client.Execute(request); vectors.Add(response.Data.Vectors); res = res && response.IsSuccessful; - }); + });*/ data.Add("Features", JToken.FromObject(vectors)); diff --git a/BotSharp.Core/Engines/TrainingCorpus.cs b/BotSharp.Core/Engines/TrainingCorpus.cs new file mode 100644 index 00000000..c2d9c69f --- /dev/null +++ b/BotSharp.Core/Engines/TrainingCorpus.cs @@ -0,0 +1,14 @@ +using BotSharp.Core.Models; +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Core.Engines +{ + public class TrainingCorpus + { + public List> UserSays { get; set; } + + public List Entities { get; set; } + } +} diff --git a/BotSharp.Core/Engines/TrainingEntity.cs b/BotSharp.Core/Engines/TrainingEntity.cs new file mode 100644 index 00000000..8c73135a --- /dev/null +++ b/BotSharp.Core/Engines/TrainingEntity.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Core.Engines +{ + public class TrainingEntity + { + public virtual String EntityType { get; set; } + + public virtual String EntityValue { get; set; } + + public List Synonyms { get; set; } + } +} diff --git a/BotSharp.Core/Engines/TrainingIntentExpression.cs b/BotSharp.Core/Engines/TrainingIntentExpression.cs new file mode 100644 index 00000000..1a8fa034 --- /dev/null +++ b/BotSharp.Core/Engines/TrainingIntentExpression.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Core.Engines +{ + public class TrainingIntentExpression where TPart : TrainingIntentExpressionPart + { + public String Text { get; set; } + public String Intent { get; set; } + + [JsonIgnore] + public String ContextHash { get; set; } + + public List Entities { get; set; } + } +} diff --git a/BotSharp.Core/Engines/TrainingIntentExpressionPart.cs b/BotSharp.Core/Engines/TrainingIntentExpressionPart.cs new file mode 100644 index 00000000..d5cf5d2a --- /dev/null +++ b/BotSharp.Core/Engines/TrainingIntentExpressionPart.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Core.Engines +{ + public class TrainingIntentExpressionPart + { + public int Start { get; set; } + public int End { get; set; } + public String Value { get; set; } + public String Entity { get; set; } + } +} diff --git a/BotSharp.RestApi/AgentController.cs b/BotSharp.RestApi/AgentController.cs index 2cea7483..49bc2de2 100644 --- a/BotSharp.RestApi/AgentController.cs +++ b/BotSharp.RestApi/AgentController.cs @@ -1,11 +1,21 @@ -using Microsoft.AspNetCore.Mvc; +using BotSharp.Core.Agents; +using BotSharp.Core.Engines; +using BotSharp.Core.Models; +using EntityFrameworkCore.BootKit; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Text; namespace BotSharp.RestApi { - [Route("[controller]/[action]")] + /// + /// Agent + /// + [Route("v1/[controller]/[action]")] public class AgentController : ControllerBase { /// @@ -16,7 +26,28 @@ namespace BotSharp.RestApi [HttpGet("{agentId}")] public ActionResult Restore([FromRoute] String agentId) { + var botsHeaderFilePath = $"{Database.ContentRootPath}App_Data{Path.DirectorySeparatorChar}DbInitializer{Path.DirectorySeparatorChar}Agents{Path.DirectorySeparatorChar}agents.json"; + var agents = JsonConvert.DeserializeObject>(System.IO.File.ReadAllText(botsHeaderFilePath)); + + var rasa = new RasaAi(); + var agentHeader = agents.First(x => x.Id == agentId); + rasa.RestoreAgent(agentHeader); + return Ok(); } + + /// + /// Dump agent + /// + /// + /// + [HttpGet("{agentId}")] + public ActionResult Dump([FromRoute] String agentId) + { + var rasa = new RasaAi(); + var agent = rasa.LoadAgent(agentId); + + return Ok(agent); + } } } diff --git a/BotSharp.RestApi/BotSharp.RestApi.csproj b/BotSharp.RestApi/BotSharp.RestApi.csproj index e2d8172e..ed3204a0 100644 --- a/BotSharp.RestApi/BotSharp.RestApi.csproj +++ b/BotSharp.RestApi/BotSharp.RestApi.csproj @@ -4,6 +4,10 @@ netcoreapp2.1 + + bin\Debug\netcoreapp2.1\BotSharp.RestApi.xml + + diff --git a/BotSharp.RestApi/ConversationController.cs b/BotSharp.RestApi/ConversationController.cs new file mode 100644 index 00000000..98786113 --- /dev/null +++ b/BotSharp.RestApi/ConversationController.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.RestApi +{ + [Route("v1/[controller]/[action]")] + public class ConversationController : ControllerBase + { + + } +} diff --git a/BotSharp.RestApi/IntentController.cs b/BotSharp.RestApi/IntentController.cs new file mode 100644 index 00000000..9dbaea48 --- /dev/null +++ b/BotSharp.RestApi/IntentController.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.RestApi +{ + [Route("v1/[controller]/[action]")] + public class IntentController : ControllerBase + { + } +} diff --git a/BotSharp.UnitTest/AgentTest.cs b/BotSharp.UnitTest/AgentTest.cs index 1792906e..1ea9d696 100644 --- a/BotSharp.UnitTest/AgentTest.cs +++ b/BotSharp.UnitTest/AgentTest.cs @@ -5,6 +5,7 @@ using BotSharp.Core.Models; using EntityFrameworkCore.BootKit; using Microsoft.EntityFrameworkCore; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; @@ -22,13 +23,11 @@ namespace BotSharp.UnitTest var agent = new Agent { Id = BOT_ID, - Name = BOT_NAME, Language = "en", UserId = Guid.NewGuid().ToString() }; - var rasa = new RasaAi(dc); - rasa.agent = agent; - int row = dc.DbTran(() => rasa.agent.SaveAgent(dc)); + var rasa = new RasaAi(); + //int row = dc.DbTran(() => rasa.agent.SaveAgent(dc)); } [TestMethod] @@ -37,38 +36,31 @@ namespace BotSharp.UnitTest var agent = new Agent { Id = BOT_ID, - Name = BOT_NAME, Language = "en" }; - var rasa = new RasaAi(dc); - rasa.agent = agent; - int row = dc.DbTran(() => rasa.agent.SaveAgent(dc)); + var rasa = new RasaAi(); + //int row = dc.DbTran(() => rasa.agent.SaveAgent(dc)); } [TestMethod] - public void RestoreAgentTest() + public void RestoreAgentFromDialogflowToRasaTest() { - var rasa = new RasaAi(dc); - var importer = new AgentImporterInDialogflow(); + var botsHeaderFilePath = $"{Database.ContentRootPath}App_Data{Path.DirectorySeparatorChar}DbInitializer{Path.DirectorySeparatorChar}Agents{Path.DirectorySeparatorChar}agents.json"; + var agents = JsonConvert.DeserializeObject>(File.ReadAllText(botsHeaderFilePath)); - string dataDir = $"{Database.ContentRootPath}App_Data{Path.DirectorySeparatorChar}DbInitializer{Path.DirectorySeparatorChar}Agents{Path.DirectorySeparatorChar}"; - var agent = rasa.RestoreAgent(importer, BOT_NAME, dataDir); - agent.Id = BOT_ID; - agent.ClientAccessToken = BOT_CLIENT_TOKEN; - agent.DeveloperAccessToken = BOT_DEVELOPER_TOKEN; - agent.UserId = Guid.NewGuid().ToString(); - rasa.agent = agent; - - int row = dc.DbTran(() => rasa.agent.SaveAgent(dc)); + agents.ForEach(agentHeader => { + var rasa = new RasaAi(); + rasa.RestoreAgent(agentHeader); + }); } [TestMethod] public void TrainAgentTest() { - var config = new AIConfiguration(BOT_CLIENT_TOKEN, SupportedLanguage.English); + var config = new AIConfiguration("", SupportedLanguage.English) { AgentId = BOT_ID }; config.SessionId = Guid.NewGuid().ToString(); - var rasa = new RasaAi(dc, config); + var rasa = new RasaAi(); rasa.Train(); } diff --git a/BotSharp.UnitTest/BotSharp.UnitTest.csproj b/BotSharp.UnitTest/BotSharp.UnitTest.csproj index 5ed76d0e..ca7277c4 100644 --- a/BotSharp.UnitTest/BotSharp.UnitTest.csproj +++ b/BotSharp.UnitTest/BotSharp.UnitTest.csproj @@ -9,7 +9,7 @@ - + diff --git a/BotSharp.UnitTest/BotTrainerTest.cs b/BotSharp.UnitTest/BotTrainerTest.cs index 4b006bf5..f7d25bcc 100644 --- a/BotSharp.UnitTest/BotTrainerTest.cs +++ b/BotSharp.UnitTest/BotTrainerTest.cs @@ -13,13 +13,13 @@ namespace BotSharp.UnitTest [TestMethod] public void TrainingTest() { - var config = new AIConfiguration(BOT_CLIENT_TOKEN, SupportedLanguage.English); + var config = new AIConfiguration("", SupportedLanguage.English) { AgentId = BOT_ID }; config.SessionId = Guid.NewGuid().ToString(); - var rasa = new RasaAi(dc, config); + var rasa = new RasaAi(); var trainer = new BotTrainer(BOT_ID, dc); - trainer.Train(rasa.agent); + trainer.Train(rasa.LoadAgent(BOT_ID)); } } } diff --git a/BotSharp.UnitTest/ConversationTest.cs b/BotSharp.UnitTest/ConversationTest.cs index 0452d544..c412c005 100644 --- a/BotSharp.UnitTest/ConversationTest.cs +++ b/BotSharp.UnitTest/ConversationTest.cs @@ -14,10 +14,11 @@ namespace BotSharp.UnitTest [TestMethod] public void TextRequest() { - var config = new AIConfiguration(BOT_CLIENT_TOKEN, SupportedLanguage.English); - config.SessionId = Guid.NewGuid().ToString(); + var rasa = new RasaAi(); + var agent = rasa.LoadAgent(BOT_ID); - var rasa = new RasaAi(dc, config); + var config = new AIConfiguration(agent.ClientAccessToken, SupportedLanguage.English) { AgentId = BOT_ID }; + config.SessionId = Guid.NewGuid().ToString(); // Round 1 var response = rasa.TextRequest(new AIRequest { Query = new String[] { "Can you play country music?" } }); diff --git a/BotSharp.UnitTest/TestEssential.cs b/BotSharp.UnitTest/TestEssential.cs index 885065c8..61f03cfc 100644 --- a/BotSharp.UnitTest/TestEssential.cs +++ b/BotSharp.UnitTest/TestEssential.cs @@ -11,9 +11,6 @@ namespace BotSharp.UnitTest public abstract class TestEssential { public static String BOT_ID = "6a9fd374-c43d-447a-97f2-f37540d0c725"; - public static String BOT_CLIENT_TOKEN = "43a0f48e3f1e41da822092e7e699426b"; - public static String BOT_DEVELOPER_TOKEN = "cd1e4685c6a04d7db1f59e6853fd597b"; - public static String BOT_NAME = "Spotify"; protected Database dc { get; set; } protected string contentRoot; diff --git a/BotSharp.WebHost/BotSharp.WebHost.csproj b/BotSharp.WebHost/BotSharp.WebHost.csproj index efcd6af0..458f02fd 100644 --- a/BotSharp.WebHost/BotSharp.WebHost.csproj +++ b/BotSharp.WebHost/BotSharp.WebHost.csproj @@ -100,6 +100,11 @@ + + + + + diff --git a/BotSharp.WebHost/Settings/app.json b/BotSharp.WebHost/Settings/app.json index 26bb0ac7..497ba711 100644 --- a/BotSharp.WebHost/Settings/app.json +++ b/BotSharp.WebHost/Settings/app.json @@ -1,15 +1,3 @@ { - "Logging": { - "IncludeScopes": false, - "Debug": { - "LogLevel": { - "Default": "Warning" - } - }, - "Console": { - "LogLevel": { - "Default": "Warning" - } - } - } + "Assemblies": "BotSharp.Core" } diff --git a/BotSharp.WebHost/Settings/logging.json b/BotSharp.WebHost/Settings/logging.json new file mode 100644 index 00000000..26bb0ac7 --- /dev/null +++ b/BotSharp.WebHost/Settings/logging.json @@ -0,0 +1,15 @@ +{ + "Logging": { + "IncludeScopes": false, + "Debug": { + "LogLevel": { + "Default": "Warning" + } + }, + "Console": { + "LogLevel": { + "Default": "Warning" + } + } + } +} diff --git a/BotSharp.WebHost/Settings/swagger.json b/BotSharp.WebHost/Settings/swagger.json new file mode 100644 index 00000000..8d3b771c --- /dev/null +++ b/BotSharp.WebHost/Settings/swagger.json @@ -0,0 +1,19 @@ +{ + "Swagger": { + "Contact": { + "Email": "haiping008@gmail.com", + "Name": "Haiping Chen", + "Url": "https://github.com/Oceania2018" + }, + "Description": "BotSharp is a chatbot platform written in C# (.net core), and it's developed for enterprise usage.", + "Endpoint": "/swagger/v1/swagger.json", + "License": { + "Name": "Apache License 2.0", + "Url": "https://github.com/Oceania2018/BotSharp/blob/master/LICENSE" + }, + "TermsOfService": "http://www.apache.org/licenses/", + "Title": "BotSharp API", + "Version": "v1", + "Stylesheet": "/swagger.css" + } +} diff --git a/BotSharp.WebHost/Startup.cs b/BotSharp.WebHost/Startup.cs index 43fd69d7..509ac10f 100644 --- a/BotSharp.WebHost/Startup.cs +++ b/BotSharp.WebHost/Startup.cs @@ -7,7 +7,9 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.PlatformAbstractions; using Newtonsoft.Json.Serialization; +using Swashbuckle.AspNetCore.Swagger; namespace BotSharp.WebHost { @@ -22,6 +24,8 @@ namespace BotSharp.WebHost public void ConfigureServices(IServiceCollection services) { + services.AddCors(); + services.AddMvc(options => { options.RespectBrowserAcceptHeader = true; @@ -30,6 +34,15 @@ namespace BotSharp.WebHost options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); + + services.AddSwaggerGen(c => + { + var info = Configuration.GetSection("Swagger").Get(); + c.SwaggerDoc(info.Version, info); + + var filePath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "BotSharp.RestApi.xml"); + c.IncludeXmlComments(filePath); + }); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) @@ -39,11 +52,32 @@ namespace BotSharp.WebHost app.UseDeveloperExceptionPage(); } + app.UseDefaultFiles(); + app.UseStaticFiles(); + + app.UseSwagger(c => + { + + }); + app.UseSwaggerUI(c => + { + var info = Configuration.GetSection("Swagger").Get(); + + c.SupportedSubmitMethods(SubmitMethod.Get, SubmitMethod.Post, SubmitMethod.Put, SubmitMethod.Patch, SubmitMethod.Delete); + c.ShowExtensions(); + c.SwaggerEndpoint(Configuration.GetValue("Swagger:Endpoint"), info.Title); + c.RoutePrefix = String.Empty; + c.DocumentTitle = info.Title; + c.InjectStylesheet(Configuration.GetValue("Swagger:Stylesheet")); + }); + + app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials()); + app.UseMvc(); Database.Configuration = Configuration; Database.ContentRootPath = env.ContentRootPath; - Database.Assemblies = new String[] { "BotSharp.Core" }; + Database.Assemblies = Configuration.GetValue("Assemblies").Split(','); } } } diff --git a/BotSharp.WebHost/wwwroot/images/BotSharp.png b/BotSharp.WebHost/wwwroot/images/BotSharp.png new file mode 100644 index 00000000..defe10f9 Binary files /dev/null and b/BotSharp.WebHost/wwwroot/images/BotSharp.png differ diff --git a/BotSharp.WebHost/wwwroot/images/BotSharp.psd b/BotSharp.WebHost/wwwroot/images/BotSharp.psd new file mode 100644 index 00000000..db98df7b Binary files /dev/null and b/BotSharp.WebHost/wwwroot/images/BotSharp.psd differ diff --git a/BotSharp.WebHost/wwwroot/swagger.css b/BotSharp.WebHost/wwwroot/swagger.css new file mode 100644 index 00000000..877e3e72 --- /dev/null +++ b/BotSharp.WebHost/wwwroot/swagger.css @@ -0,0 +1,3 @@ +.topbar-wrapper a span { + visibility: hidden; +}