add: 解析语法树和对话机器人
This commit is contained in:
parent
9c27d534ce
commit
ccaefdc6cc
|
@ -12,15 +12,16 @@ public class DefaultChatRobot : IChatRobot
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public string RobotName => "凯瑟琳";
|
||||
public string RobotName => "Default";
|
||||
|
||||
public IEnumerable<string> OnChatStart()
|
||||
{
|
||||
_logger.LogDebug("Start default chat robot.");
|
||||
return new[]
|
||||
{
|
||||
"向着星辰与深渊!",
|
||||
"欢迎来到冒险家协会。"
|
||||
"坏了,被你发现默认机器人了。",
|
||||
"使用这个粪机器人,怎么能得高分呢?",
|
||||
"必须要出重拳!"
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,7 @@ public class DefaultChatRobot : IChatRobot
|
|||
_logger.LogDebug("End default chat robot.");
|
||||
return new[]
|
||||
{
|
||||
"再见,感谢您对协会做出的贡献,冒险家。"
|
||||
"我不到啊。"
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,7 +39,7 @@ public class DefaultChatRobot : IChatRobot
|
|||
_logger.LogDebug("Robot receive message: \"{}\".", input);
|
||||
return new[]
|
||||
{
|
||||
"暂时不支持该功能,请联系维护人员。"
|
||||
"啊对对对。"
|
||||
};
|
||||
}
|
||||
}
|
22
Katheryne/Exceptions/GrammarException.cs
Normal file
22
Katheryne/Exceptions/GrammarException.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
namespace Katheryne.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// 语法中存在的错误
|
||||
/// </summary>
|
||||
public class GrammarException : Exception
|
||||
{
|
||||
public GrammarException() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GrammarException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GrammarException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
54
Katheryne/KatheryneChatRobot.cs
Normal file
54
Katheryne/KatheryneChatRobot.cs
Normal file
|
@ -0,0 +1,54 @@
|
|||
using Katheryne.Abstractions;
|
||||
using Katheryne.Models;
|
||||
using Katheryne.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Katheryne;
|
||||
|
||||
public class KatheryneChatRobot : IChatRobot
|
||||
{
|
||||
private readonly ILogger<KatheryneChatRobot> _logger;
|
||||
private readonly GrammarTree _grammarTree;
|
||||
|
||||
private string _currentStage;
|
||||
|
||||
public KatheryneChatRobot(GrammarTree grammarTree, ILogger<KatheryneChatRobot> logger,
|
||||
string beginStage, string robotName)
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
_grammarTree = grammarTree;
|
||||
_currentStage = beginStage;
|
||||
RobotName = robotName;
|
||||
}
|
||||
|
||||
public string RobotName { get; }
|
||||
public IEnumerable<string> OnChatStart()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
_grammarTree[_currentStage]
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<string> OnChatStop()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
"再见。"
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<string> ChatNext(string input)
|
||||
{
|
||||
_logger.LogDebug("Receive input {} on stage {}.", input, _currentStage);
|
||||
(_currentStage, string answer) = _grammarTree.NextStage(_currentStage, input);
|
||||
_logger.LogDebug("Change stage to {}.", _currentStage);
|
||||
|
||||
return new[]
|
||||
{
|
||||
answer
|
||||
};
|
||||
}
|
||||
}
|
109
Katheryne/Models/GrammarTree.cs
Normal file
109
Katheryne/Models/GrammarTree.cs
Normal file
|
@ -0,0 +1,109 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using Katheryne.Exceptions;
|
||||
|
||||
namespace Katheryne.Models;
|
||||
|
||||
public class GrammarTree
|
||||
{
|
||||
private readonly Dictionary<string, InnerStage> _stages = new();
|
||||
|
||||
public GrammarTree(LexicalModel model)
|
||||
{
|
||||
foreach (Stage stage in model.Stages)
|
||||
{
|
||||
_stages[stage.Name] = new InnerStage(stage);
|
||||
}
|
||||
|
||||
if (!Validate(model))
|
||||
{
|
||||
throw new GrammarException("使用了未声明的阶段名");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得下一个阶段
|
||||
/// </summary>
|
||||
/// <param name="currentStage">当前所在阶段</param>
|
||||
/// <param name="input">用户输入</param>
|
||||
/// <returns>元组,第一个参数是下一个阶段名称 第二个参数是机器人回答</returns>
|
||||
/// <exception cref="GrammarException"></exception>
|
||||
public (string, string) NextStage(string currentStage, string input)
|
||||
{
|
||||
List<InnerTransformer> transformers = _stages[currentStage].Transformers;
|
||||
|
||||
foreach (InnerTransformer transformer in transformers)
|
||||
{
|
||||
Match match = transformer.Pattern.Match(input);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
return (_stages[transformer.NextStage].Name,
|
||||
_stages[transformer.NextStage].Answer);
|
||||
}
|
||||
}
|
||||
|
||||
throw new GrammarException("Failed to get next stage.");
|
||||
}
|
||||
|
||||
public string this[string index] => _stages[index].Answer;
|
||||
|
||||
/// <summary>
|
||||
/// 主要验证语法的两个特点
|
||||
/// 1. 起始阶段是否被定义
|
||||
/// 2. 每个Transformer的下一个阶段是否被定义
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Validate(LexicalModel model)
|
||||
{
|
||||
if (!_stages.ContainsKey(model.BeginStageName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return model.Stages.All((stage) =>
|
||||
{
|
||||
return stage.Transformers.All(t => _stages.ContainsKey(t.NextStageName));
|
||||
});
|
||||
}
|
||||
|
||||
private class InnerStage
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public List<InnerTransformer> Transformers { get; } = new();
|
||||
|
||||
public string Answer { get; }
|
||||
|
||||
public InnerStage(Stage stage)
|
||||
{
|
||||
Name = stage.Name;
|
||||
Answer = stage.Answer;
|
||||
|
||||
foreach (Transformer transformer in stage.Transformers)
|
||||
{
|
||||
Transformers.Add(new InnerTransformer(transformer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class InnerTransformer
|
||||
{
|
||||
public Regex Pattern { get; }
|
||||
|
||||
public string NextStage { get; }
|
||||
|
||||
public InnerTransformer(Transformer transformer)
|
||||
{
|
||||
NextStage = transformer.NextStageName;
|
||||
|
||||
try
|
||||
{
|
||||
Pattern = new Regex(transformer.Pattern);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
throw new GrammarException($"Failed to Parse regex:{transformer.Pattern}.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
Katheryne/ServiceCollectionExtensions.cs
Normal file
14
Katheryne/ServiceCollectionExtensions.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using Katheryne.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Katheryne;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static void AddYamlDeserializerFactory(this IServiceCollection collection)
|
||||
{
|
||||
collection.AddSingleton<YamlDeserializerFactory>();
|
||||
collection.AddSingleton<DefaultChatRobot>();
|
||||
collection.AddScoped<KatheryneChatRobotFactory>();
|
||||
}
|
||||
}
|
51
Katheryne/Services/KatheryneChatRobotFactory.cs
Normal file
51
Katheryne/Services/KatheryneChatRobotFactory.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using Katheryne.Abstractions;
|
||||
using Katheryne.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Katheryne.Services;
|
||||
|
||||
public class KatheryneChatRobotFactory
|
||||
{
|
||||
private readonly YamlDeserializerFactory _deserializerFactory;
|
||||
private readonly ILogger<KatheryneChatRobotFactory> _factoryLogger;
|
||||
private readonly ILogger<KatheryneChatRobot> _robotLogger;
|
||||
private readonly DefaultChatRobot _defaultChatRobot;
|
||||
|
||||
private Grammar? _grammar;
|
||||
|
||||
public KatheryneChatRobotFactory(YamlDeserializerFactory deserializerFactory,
|
||||
ILogger<KatheryneChatRobotFactory> factoryLogger,
|
||||
ILogger<KatheryneChatRobot> robotLogger,
|
||||
DefaultChatRobot defaultChatRobot)
|
||||
{
|
||||
_deserializerFactory = deserializerFactory;
|
||||
_factoryLogger = factoryLogger;
|
||||
_robotLogger = robotLogger;
|
||||
_defaultChatRobot = defaultChatRobot;
|
||||
}
|
||||
|
||||
public void SetGrammar(string grammarText)
|
||||
{
|
||||
_factoryLogger.LogInformation("Receive new grammar: {}.", grammarText);
|
||||
IDeserializer deserializer = _deserializerFactory.GetDeserializer();
|
||||
|
||||
LexicalModel model = deserializer.Deserialize<LexicalModel>(grammarText);
|
||||
_grammar = new Grammar(new GrammarTree(model), model.RobotName, model.BeginStageName);
|
||||
}
|
||||
|
||||
public IChatRobot GetRobot()
|
||||
{
|
||||
if (_grammar is null)
|
||||
{
|
||||
_factoryLogger.LogDebug("Get default chat robot.");
|
||||
return _defaultChatRobot;
|
||||
}
|
||||
|
||||
_factoryLogger.LogDebug("Get chat robot: {}.", _grammar.RobotName);
|
||||
return new KatheryneChatRobot(_grammar.GrammarTree, _robotLogger,
|
||||
_grammar.BeginStage, _grammar.RobotName);
|
||||
}
|
||||
|
||||
private record Grammar(GrammarTree GrammarTree, string RobotName, string BeginStage);
|
||||
}
|
Loading…
Reference in New Issue
Block a user