BotSharp/Platform.Articulate/ArticulateAi.cs
2018-10-02 20:44:11 -05:00

230 lines
7.9 KiB
C#

using BotSharp.Core;
using BotSharp.Core.Agents;
using BotSharp.Core.Engines;
using BotSharp.Models.NLP;
using BotSharp.Platform.Abstraction;
using BotSharp.Platform.Models;
using BotSharp.Platform.Models.AiRequest;
using BotSharp.Platform.Models.AiResponse;
using DotNetToolkit;
using Platform.Articulate.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Platform.Articulate
{
/// <summary>
/// A platform for building conversational interfaces with intelligent agents (chatbots)
/// http://spg.ai/projects/articulate
/// This implementation takes over APIs of Articulate's 7500 port.
/// </summary>
public class ArticulateAi<TAgent> :
PlatformBuilderBase<TAgent>,
IPlatformBuilder<TAgent>
where TAgent : AgentModel
{
public DialogRequestOptions RequestOptions { get; set; }
public Tuple<TAgent, DomainModel> GetAgentByDomainId(String domainId)
{
var results = GetAllAgents();
foreach (TAgent agent in results)
{
var domain = agent.Domains.FirstOrDefault(x => x.Id == domainId);
if (domain != null)
{
return new Tuple<TAgent, DomainModel>(agent, domain);
}
}
return null;
}
public Tuple<TAgent, DomainModel, IntentModel> GetAgentByIntentId(String intentId)
{
var results = GetAllAgents();
foreach (TAgent agent in results)
{
foreach (DomainModel domain in agent.Domains)
{
var intent = domain.Intents.FirstOrDefault(x => x.Id == intentId);
if (intent != null)
{
return new Tuple<TAgent, DomainModel, IntentModel>(agent, domain, intent);
}
}
}
return null;
}
public List<IntentModel> GetReferencedIntentsByEntity(string entityId)
{
var intents = new List<IntentModel>();
var allAgents = GetAllAgents();
foreach (TAgent agent in allAgents)
{
foreach (DomainModel domain in agent.Domains)
{
foreach (IntentModel intent in domain.Intents)
{
if(intent.Examples.Exists(x => x.Entities.Exists(y => y.EntityId == entityId)))
{
intents.Add(intent);
}
}
}
}
return intents;
}
public TrainingCorpus ExtractorCorpus(TAgent agent)
{
var corpus = new TrainingCorpus();
corpus.Entities = agent.Entities.Select(x => new TrainingEntity
{
Entity = x.EntityName,
Values = x.Examples.Select(y => new TrainingEntitySynonym
{
Value = y.Value,
Synonyms = y.Synonyms
}).ToList()
}).ToList();
corpus.UserSays = new List<TrainingIntentExpression<TrainingIntentExpressionPart>>();
foreach(DomainModel domain in agent.Domains)
{
foreach(IntentModel intent in domain.Intents)
{
foreach(IntentExampleModel example in intent.Examples)
{
var say = new TrainingIntentExpression<TrainingIntentExpressionPart>()
{
Intent = intent.IntentName,
Text = example.UserSays,
Entities = example.Entities.Select(x => new TrainingIntentExpressionPart
{
Entity = x.Entity,
Start = x.Start,
Value = x.Value
}).ToList()
};
corpus.UserSays.Add(say);
}
}
}
return corpus;
}
public override bool SaveAgent(TAgent agent)
{
agent.Status = "Changed";
agent.LastTraining = DateTime.UtcNow;
return base.SaveAgent(agent);
}
public async Task<bool> Train(TAgent agent, TrainingCorpus corpus)
{
string agentDir = Path.Combine(AppDomain.CurrentDomain.GetData("DataPath").ToString(), "Projects", agent.Id);
// save corpus to agent dir
var projectPath = Path.Combine(AppDomain.CurrentDomain.GetData("DataPath").ToString(), "Projects", agent.Id);
var model = "model_" + DateTime.UtcNow.ToString("yyyyMMdd");
var modelPath = Path.Combine(projectPath, model);
var trainer = new BotTrainer();
var parsedAgent = agent.ToObject<Agent>();
var intents = new List<TrainingIntentExpression<TrainingIntentExpressionPart>>();
foreach (DomainModel domain in (agent as AgentModel).Domains)
{
foreach (IntentModel intent in domain.Intents)
{
foreach (IntentExampleModel example in intent.Examples)
{
var parsedIntent = new TrainingIntentExpression<TrainingIntentExpressionPart>
{
Intent = intent.IntentName,
Text = example.UserSays,
Entities = example.Entities.Select(x => new TrainingIntentExpressionPart
{
Entity = x.Entity,
Start = x.Start,
Value = x.Value
}).ToList()
};
intents.Add(parsedIntent);
}
}
}
parsedAgent.Corpus = new TrainingCorpus
{
Entities = (agent as AgentModel).Entities.Select(x => new TrainingEntity
{
Entity = x.EntityName,
Values = x.Examples.Select(y => new TrainingEntitySynonym
{
Value = y.Value,
Synonyms = y.Synonyms
}).ToList()
}).ToList(),
UserSays = intents
};
var trainOptions = new BotTrainOptions
{
AgentDir = projectPath,
Model = model
};
var info = await trainer.Train(parsedAgent, trainOptions);
return true;
}
public AiResponse TextRequest(AiRequest request)
{
var aiResponse = new AiResponse();
// Load agent
var projectPath = Path.Combine(AppDomain.CurrentDomain.GetData("DataPath").ToString(), "Projects", request.AgentId);
var model = Directory.GetDirectories(projectPath).Where(x => x.Contains("model_")).Last().Split(Path.DirectorySeparatorChar).Last();
var modelPath = Path.Combine(projectPath, model);
request.AgentDir = projectPath;
request.Model = model;
var agent = GetAgentById(request.AgentId);
var preditor = new BotPredictor();
var doc = preditor.Predict(agent.ToObject<Agent>(), request).Result;
var parameters = new Dictionary<String, Object>();
if (doc.Sentences[0].Entities == null)
{
doc.Sentences[0].Entities = new List<NlpEntity>();
}
doc.Sentences[0].Entities.ForEach(x => parameters[x.Entity] = x.Value);
aiResponse.Intent = doc.Sentences[0].Intent.Label;
aiResponse.Speech = aiResponse.Intent;
return aiResponse;
}
}
}