|
@@ -4,165 +4,124 @@ namespace Yuuna.Contracts.Plugins
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Collections.Immutable;
|
|
|
- using System.Linq;
|
|
|
using System.Runtime.CompilerServices;
|
|
|
- using System.Text;
|
|
|
using Yuuna.Contracts.Interaction;
|
|
|
using Yuuna.Contracts.Optimization;
|
|
|
using Yuuna.Contracts.Patterns;
|
|
|
+ using Yuuna.Contracts.Patterns.Cascade;
|
|
|
using Yuuna.Contracts.Semantics;
|
|
|
using Yuuna.Contracts.TextSegmention;
|
|
|
- using Yuuna.Contracts.Utilities;
|
|
|
|
|
|
- public sealed class Fake : PluginBase
|
|
|
+ public delegate Response Invoke(IScore score);
|
|
|
+ public delegate Response Incomplete(IScore score);
|
|
|
+
|
|
|
+ public interface IInvokeCreator
|
|
|
{
|
|
|
- protected override void BuildPatterns(IGroupManager g, IPatternBuilder p)
|
|
|
- {
|
|
|
- g.Define("open").AppendOrCreate(new[] { "打開", "開" });
|
|
|
- g.Define("door").AppendOrCreate(new[] { "門", "房間門" });
|
|
|
- g.Define("light").AppendOrCreate(new[] { "燈", "檯燈" });
|
|
|
- //g.Define("browser").AppendOrCreate(new[] { "瀏覽器", "chrome" });
|
|
|
+ IIncompleteCreator OnInvoke(Invoke invoke);
|
|
|
+ }
|
|
|
|
|
|
- p.Build(g["open"], g["door"]).OnInvoke(score =>
|
|
|
- {
|
|
|
- var DOOR = new { IS_OPENED = new[] { true, false, true, false }.RandomTakeOne() };
|
|
|
- // 開門
|
|
|
- if (!DOOR.IS_OPENED)
|
|
|
- return (Moods.Happy, "已經開好門囉 <3");
|
|
|
- else
|
|
|
- return (Moods.Sad, "可是門本來就是開的欸 QAQ");
|
|
|
- });
|
|
|
-
|
|
|
- p.Build(g["open"], g["light"]).OnInvoke(score =>
|
|
|
- {
|
|
|
- var LIGHT = new { IS_OPENED = new[] { true, false,true,false }.RandomTakeOne() };
|
|
|
- // 開門
|
|
|
- if (!LIGHT.IS_OPENED)
|
|
|
- return (Moods.Happy, "已經開好燈囉 <3");
|
|
|
- else
|
|
|
- return (Moods.Sad, "可是燈本來就是開的欸 QAQ");
|
|
|
- });
|
|
|
-
|
|
|
- //p.Build(g["open"], g["browser"]).OnInvoke(score =>
|
|
|
- //{
|
|
|
- // var DOOR = new { IS_OPENED = true };
|
|
|
- // // 開門
|
|
|
- // if (!DOOR.IS_OPENED)
|
|
|
- // return (Moods.Happy, "已經開好門囉 <3");
|
|
|
- // else
|
|
|
- // return (Moods.Sad, "可是門本來就是開的欸 QAQ");
|
|
|
- //});
|
|
|
+ public interface IIncompleteCreator
|
|
|
+ {
|
|
|
+ void OnIncomplete(Incomplete incomplete);
|
|
|
+ }
|
|
|
+
|
|
|
+ public sealed class IncompleteCreator : Output<Incomplete>, IIncompleteCreator
|
|
|
+ {
|
|
|
+ public void OnIncomplete(Incomplete incomplete)
|
|
|
+ {
|
|
|
+ //if (incomplete is null)
|
|
|
+ // throw new ArgumentNullException(nameof(incomplete));
|
|
|
+ this.StoreData( incomplete);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- public class PluginHub
|
|
|
+ public sealed class InvokeCreator : Pipeline<Invoke, IncompleteCreator>, IInvokeCreator
|
|
|
{
|
|
|
- public PluginHub()
|
|
|
+ public IIncompleteCreator OnInvoke(Invoke invoke)
|
|
|
{
|
|
|
+ //if (invoke is null)
|
|
|
+ // throw new ArgumentNullException(nameof(invoke));
|
|
|
|
|
|
+ return this.StoreData(invoke);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
+ public interface IGrammarCreator
|
|
|
+ {
|
|
|
+ IInvokeCreator Build(IGroup group, params IGroup[] rest);
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
- public static void Main(string[] args)
|
|
|
- {
|
|
|
- // Send("打開門");
|
|
|
- // Send("開燈");
|
|
|
- // Send("打開燈");
|
|
|
- }
|
|
|
-
|
|
|
- public static void Send(string text)
|
|
|
+ public sealed class GrammarCreator : Pipeline<IGrammar, InvokeCreator>, IGrammarCreator
|
|
|
+ {
|
|
|
+ public IInvokeCreator Build(IGroup group, params IGroup[] rest)
|
|
|
{
|
|
|
- ITextSegmenter segmenter = new JiebaTextSegmenter();
|
|
|
- var allPlugins = new PluginBase[] { new Fake() };
|
|
|
- foreach (var item in allPlugins)
|
|
|
- {
|
|
|
- item.Initialize(segmenter);
|
|
|
- Console.WriteLine("已載入模組: "+item.GetType().AssemblyQualifiedName);
|
|
|
- }
|
|
|
-
|
|
|
- Console.WriteLine("我: " + text);
|
|
|
- var cutted = segmenter.Cut(text);
|
|
|
- Console.WriteLine($"來自分詞器 {segmenter.Name} 的分詞結果: [ {string.Join(", ",cutted)} ]");
|
|
|
- var strategy = new DefaultStrategy();
|
|
|
- var list = new List<IScore>();
|
|
|
- foreach (var p in allPlugins)
|
|
|
- list.AddRange(p.Evaluate(strategy, cutted));
|
|
|
- list.Sort(ScoreComparer.Default);
|
|
|
-
|
|
|
- var sb = new StringBuilder("Bot: ");
|
|
|
- var best = list.LastOrDefault();
|
|
|
- if (best is null)
|
|
|
- sb.Append("我不懂你的意思");
|
|
|
- else if (best.IsCompacted)
|
|
|
- {
|
|
|
- var resp = best.Plugin.SelectBest(best).Invoke(best);
|
|
|
- Console.WriteLine( resp.Mood.ToString());
|
|
|
- sb.Append(resp.Message);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- var choices = list.Where(s => s.Missing.Count <= 1).ToImmutableArray();
|
|
|
- switch (choices.Length)
|
|
|
- {
|
|
|
- case 1:
|
|
|
- {
|
|
|
- sb.Append("你" + new[] { "是想", "想要" }.RandomTakeOne() + " ");
|
|
|
- sb.Append(choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
|
|
|
- sb.Append(" 嗎?");
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
-
|
|
|
- case 2:
|
|
|
- {
|
|
|
- sb.Append("你" + new[] { "是想", "想要" }.RandomTakeOne() + " ");
|
|
|
- sb.AppendJoin(" 還是 ", choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
|
|
|
- sb.Append(" ?");
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
-
|
|
|
- default:
|
|
|
- sb.Append("我不太清楚你想做什麼");
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Console.WriteLine(sb);
|
|
|
-
|
|
|
+ //if (group is null)
|
|
|
+ // throw new ArgumentNullException(nameof(group));
|
|
|
+ var g = new Grammar();
|
|
|
+ //g.Add(group);
|
|
|
+ //if (rest != null)
|
|
|
+ // foreach (var item in rest)
|
|
|
+ // {
|
|
|
+ // g.Add(item);
|
|
|
+ // }
|
|
|
+ //g.Immute();
|
|
|
+
|
|
|
+ return this.StoreData( g);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
public abstract class PluginBase
|
|
|
{
|
|
|
- private readonly PatternBuilder _grammarSet;
|
|
|
- private readonly GroupManager _groupManager;
|
|
|
+ private readonly PatternBuilder _grammarSet;
|
|
|
|
|
|
|
|
|
public PluginBase()
|
|
|
{
|
|
|
this._grammarSet = new PatternBuilder();
|
|
|
- this._groupManager = new GroupManager();
|
|
|
}
|
|
|
|
|
|
- protected virtual void PreInitialize(ITextSegmenter segmenter)
|
|
|
+ /// <summary>
|
|
|
+ /// 在初始化前引發。
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="segmenter"></param>
|
|
|
+ protected virtual void BeforeInitialize(ITextSegmenter segmenter)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
- internal void Initialize(ITextSegmenter textSegmenter)
|
|
|
+ internal bool Initialize(ITextSegmenter textSegmenter)
|
|
|
{
|
|
|
- this.PreInitialize(textSegmenter);
|
|
|
- this.BuildPatterns(this._groupManager, this._grammarSet);
|
|
|
- textSegmenter.Load(this._groupManager);
|
|
|
- this.OnInitialize();
|
|
|
+ try
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+ this.BeforeInitialize(textSegmenter);
|
|
|
+ var groupManager = new GroupManager();
|
|
|
+ this.BuildPatterns(groupManager, this._grammarSet);
|
|
|
+ textSegmenter.Load(groupManager);
|
|
|
+ this.AfterInitialize();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
- protected virtual void OnInitialize()
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 在初始化後引發。
|
|
|
+ /// </summary>
|
|
|
+ protected virtual void AfterInitialize()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
- protected abstract void BuildPatterns(IGroupManager groupManager, IPatternBuilder grammarBuilder);
|
|
|
+ /// <summary>
|
|
|
+ /// 建立模式規則。
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="g"></param>
|
|
|
+ /// <param name="p"></param>
|
|
|
+ protected abstract void BuildPatterns(IGroupManager g, IPatternBuilder p);
|
|
|
|
|
|
internal IImmutableList<IScore> Evaluate(StrategyBase strategy, IImmutableList<string> cutted)
|
|
|
{
|
|
@@ -175,4 +134,5 @@ namespace Yuuna.Contracts.Plugins
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
}
|