|
|
@@ -0,0 +1,199 @@
|
|
|
+
|
|
|
+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.Semantics;
|
|
|
+ using Yuuna.Contracts.TextSegmention;
|
|
|
+
|
|
|
+ public sealed class Fake : PluginBase
|
|
|
+ {
|
|
|
+ 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" });
|
|
|
+
|
|
|
+ p.Build(g["open"], g["door"]).OnInvoke(score =>
|
|
|
+ {
|
|
|
+ var DOOR = new { IS_OPENED = new[] { true, false, true, false }.Random() };
|
|
|
+ // 開門
|
|
|
+ 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 }.Random() };
|
|
|
+ // 開門
|
|
|
+ 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 static class RandomHelper
|
|
|
+ {
|
|
|
+ public static T Random<T>(this IEnumerable<T> collection)
|
|
|
+ {
|
|
|
+ if (collection == null)
|
|
|
+ throw new ArgumentNullException(nameof(collection));
|
|
|
+ var list = collection.ToArray();
|
|
|
+ if (list.Length == 0)
|
|
|
+ return default(T);
|
|
|
+ else if (list.Length == 1)
|
|
|
+ return list[0];
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var rnd = new System.Random(Guid.NewGuid().GetHashCode());
|
|
|
+ var index = rnd.Next(0, list.Length);
|
|
|
+ return list[index];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public class PluginHub
|
|
|
+ {
|
|
|
+ public PluginHub()
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public static void Main(string[] args)
|
|
|
+ {
|
|
|
+ // Send("打開門");
|
|
|
+ // Send("開燈");
|
|
|
+ Send("打開燈");
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void Send(string text)
|
|
|
+ {
|
|
|
+ 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[] { "是想", "想要" }.Random() + " ");
|
|
|
+ sb.Append(choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().Random().ToImmutable().Random())));
|
|
|
+ sb.Append(" 嗎?");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+
|
|
|
+ case 2:
|
|
|
+ {
|
|
|
+ sb.Append("你" + new[] { "是想", "想要" }.Random() + " ");
|
|
|
+ sb.AppendJoin(" 還是 ", choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().Random().ToImmutable().Random())));
|
|
|
+ sb.Append(" ?");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+
|
|
|
+ default:
|
|
|
+ sb.Append("我不太清楚你想做什麼");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Console.WriteLine(sb);
|
|
|
+
|
|
|
+ //foreach (var topmost in list.Where(x=>x.IsCompacted))
|
|
|
+ //{
|
|
|
+ // Console.WriteLine(topmost.IsCompacted);
|
|
|
+ // Console.WriteLine("coverage: " + topmost.Coverage * 100.0 +" %");
|
|
|
+ // Console.WriteLine("missing: "+topmost.Missing.Count);
|
|
|
+
|
|
|
+ // Console.WriteLine(string.Join(",", topmost.Contrast.SequentialKeys));
|
|
|
+ // Console.WriteLine();
|
|
|
+ //}
|
|
|
+ //Console.ReadKey();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public abstract class PluginBase
|
|
|
+ {
|
|
|
+ private readonly PatternBuilder _grammarSet;
|
|
|
+ private readonly GroupManager _groupManager;
|
|
|
+
|
|
|
+
|
|
|
+ public PluginBase()
|
|
|
+ {
|
|
|
+ this._grammarSet = new PatternBuilder();
|
|
|
+ this._groupManager = new GroupManager();
|
|
|
+ }
|
|
|
+
|
|
|
+ internal void Initialize(ITextSegmenter textSegmenter)
|
|
|
+ {
|
|
|
+ this.BuildPatterns(this._groupManager, this._grammarSet);
|
|
|
+ textSegmenter.Load(this._groupManager);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected abstract void BuildPatterns(IGroupManager groupManager, IPatternBuilder grammarBuilder);
|
|
|
+
|
|
|
+ internal IImmutableList<IScore> Evaluate(StrategyBase strategy, IImmutableList<string> cutted)
|
|
|
+ {
|
|
|
+ return strategy.Assess(this, cutted, this._grammarSet);
|
|
|
+ }
|
|
|
+
|
|
|
+ internal Behaviour SelectBest(IScore score)
|
|
|
+ {
|
|
|
+ return this._grammarSet.TryGet(score.Contrast, out var b) ? b : null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|