add: 解析语法树和对话机器人
This commit is contained in:
		@@ -12,15 +12,16 @@ public class DefaultChatRobot : IChatRobot
 | 
				
			|||||||
        _logger = logger;
 | 
					        _logger = logger;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public string RobotName => "凯瑟琳";
 | 
					    public string RobotName => "Default";
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    public IEnumerable<string> OnChatStart()
 | 
					    public IEnumerable<string> OnChatStart()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        _logger.LogDebug("Start default chat robot.");
 | 
					        _logger.LogDebug("Start default chat robot.");
 | 
				
			||||||
        return new[]
 | 
					        return new[]
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "向着星辰与深渊!",
 | 
					            "坏了,被你发现默认机器人了。",
 | 
				
			||||||
            "欢迎来到冒险家协会。"
 | 
					            "使用这个粪机器人,怎么能得高分呢?",
 | 
				
			||||||
 | 
					            "必须要出重拳!"
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,7 +30,7 @@ public class DefaultChatRobot : IChatRobot
 | 
				
			|||||||
        _logger.LogDebug("End default chat robot.");
 | 
					        _logger.LogDebug("End default chat robot.");
 | 
				
			||||||
        return new[]
 | 
					        return new[]
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "再见,感谢您对协会做出的贡献,冒险家。"
 | 
					            "我不到啊。"
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,7 +39,7 @@ public class DefaultChatRobot : IChatRobot
 | 
				
			|||||||
        _logger.LogDebug("Robot receive message: \"{}\".", input);
 | 
					        _logger.LogDebug("Robot receive message: \"{}\".", input);
 | 
				
			||||||
        return new[]
 | 
					        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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user