|
@@ -4,7 +4,7 @@
|
|
|
namespace Yuuna
|
|
|
{
|
|
|
using System;
|
|
|
- using System.Text;
|
|
|
+ using System.Text;
|
|
|
|
|
|
using Yuuna.Contracts.Optimization;
|
|
|
using Yuuna.Contracts.Modules;
|
|
@@ -18,6 +18,7 @@ namespace Yuuna
|
|
|
using System.Linq;
|
|
|
using Yuuna.Contracts.Interaction;
|
|
|
using System.Diagnostics;
|
|
|
+ using System.Collections.Generic;
|
|
|
|
|
|
public class Antonym
|
|
|
{
|
|
@@ -81,27 +82,154 @@ namespace Yuuna
|
|
|
public override string ToString() => (this._words[0].Value + " / " + this._words[1].Value).ToString();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- public interface IInteractiveView
|
|
|
+ public class DefaultAcceptor
|
|
|
{
|
|
|
- string Accept();
|
|
|
- void OnReceive(Response response);
|
|
|
- }
|
|
|
+ private readonly Response[] _canResponses;
|
|
|
+ private readonly Antonym[] _antonyms;
|
|
|
+ private readonly ITextSegmenter _segmenter;
|
|
|
+ private readonly IStrategy _plan;
|
|
|
+ private readonly IReadOnlyList<ModuleProxy> _allPlugins;
|
|
|
+ private readonly Stack<Match> _session;
|
|
|
+
|
|
|
+ public DefaultAcceptor()
|
|
|
+ {
|
|
|
+ this._canResponses = new Response[]
|
|
|
+ {
|
|
|
+ (Moods.Sad, "我不清楚你想做什麼 OvQ"),
|
|
|
+ (Moods.Sad, "我不懂你想幹嘛 QAQ"),
|
|
|
+ (Moods.Sad, "我不知道你想幹嘛 OHQ"),
|
|
|
+ };
|
|
|
|
|
|
- public sealed class ConsoleBotInteract : IInteractiveView
|
|
|
- {
|
|
|
- public string Name { get; }
|
|
|
+ this._antonyms = new[]
|
|
|
+ {
|
|
|
+ new Antonym("是", "不是"),
|
|
|
+ new Antonym("對", "不對"),
|
|
|
+ new Antonym("是", "否"),
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ this._segmenter = new JiebaTextSegmenter();
|
|
|
+ this._plan = new DefaultStrategy();
|
|
|
+
|
|
|
+ this._allPlugins = ModuleManager.Instance.Modules;
|
|
|
+ foreach (var plugin in this._allPlugins)
|
|
|
+ {
|
|
|
+ plugin.Initialize(this._segmenter, new GroupManager());
|
|
|
+ Debug.WriteLine("已載入模組: " + plugin.Type.AssemblyQualifiedName);
|
|
|
+ }
|
|
|
|
|
|
- public ConsoleBotInteract(string name)
|
|
|
+ this._session = new Stack<Match>();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public virtual Response OnAccept(string text)
|
|
|
{
|
|
|
- if (string.IsNullOrWhiteSpace(name))
|
|
|
- throw new ArgumentException( "", nameof(name));
|
|
|
- this.Name = name;
|
|
|
+ var cutted = this._segmenter.Cut(text);
|
|
|
+ //Debug.WriteLine($"來自分詞器 {this._segmenter.Name} 的分詞結果: [ {string.Join(", ", cutted)} ]");
|
|
|
+
|
|
|
+ if (this._session.Count > 0)
|
|
|
+ {
|
|
|
+ var single = this._session.Pop();
|
|
|
+
|
|
|
+ foreach (var antonym in this._antonyms)
|
|
|
+ {
|
|
|
+ if (antonym.Judge(text, out var type))
|
|
|
+ {
|
|
|
+ if (type.Equals(Antonym.TypeKinds.Positive))
|
|
|
+ {
|
|
|
+ single.Pattern.Owner.Patterns.TryGet(single.Pattern, out var bag);
|
|
|
+ var r = bag.Invoke(single);
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (this._session.Count == 0)
|
|
|
+ return this._canResponses.RandomTakeOne();
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var sb = new StringBuilder("還是你是想");
|
|
|
+ foreach (var g in this._session.Peek().Pattern.ToImmutable())
|
|
|
+ sb.Append(g.RandomTakeOne().RandomTakeOne());
|
|
|
+ sb.Append("?");
|
|
|
+ return sb.ToString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ var alternative = this._plan.FindBest(this._allPlugins.Select(x => x.PatternSet).ToArray(), cutted);
|
|
|
+ //Debug.WriteLine(alternative.Status);
|
|
|
+ switch (alternative.Status)
|
|
|
+ {
|
|
|
+ // 罐頭回應
|
|
|
+ case AlternativeStatus.Invalid:
|
|
|
+ return this._canResponses.RandomTakeOne();
|
|
|
+
|
|
|
+ case AlternativeStatus.Optimal:
|
|
|
+ {
|
|
|
+ var single = alternative.Matches[0];
|
|
|
+ single.Pattern.Owner.Patterns.TryGet(single.Pattern, out var bag);
|
|
|
+ var r = bag.Invoke(single);
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+
|
|
|
+ case AlternativeStatus.Condition:
|
|
|
+ {
|
|
|
+ var sb = new StringBuilder();
|
|
|
+
|
|
|
+ sb.Append("你是想要");
|
|
|
+ foreach (var g in alternative.Matches[0].Pattern.ToImmutable())
|
|
|
+ sb.Append(g.RandomTakeOne().RandomTakeOne());
|
|
|
+ sb.Append("嗎?");
|
|
|
+
|
|
|
+ this._session.Push(alternative.Matches[0]);
|
|
|
+ return sb.ToString();
|
|
|
+ }
|
|
|
+
|
|
|
+ case AlternativeStatus.Proposition:
|
|
|
+ {
|
|
|
+
|
|
|
+ var sb = new StringBuilder();
|
|
|
+
|
|
|
+ sb.Append("你是想要");
|
|
|
+ foreach (var g in alternative.Matches[0].Pattern.ToImmutable())
|
|
|
+ sb.Append(g.RandomTakeOne().RandomTakeOne());
|
|
|
+ sb.Append("嗎?");
|
|
|
+
|
|
|
+ this._session.Push(alternative.Matches[1]);
|
|
|
+ this._session.Push(alternative.Matches[0]);
|
|
|
+ return sb.ToString();
|
|
|
+ }
|
|
|
+
|
|
|
+ case AlternativeStatus.Paradox:
|
|
|
+
|
|
|
+
|
|
|
+ break;
|
|
|
+
|
|
|
+ //case AlternativeStatus.NoModuleInstalled:
|
|
|
+ // interactor.OnReceive((Moods.Sad, "無效的模組"));
|
|
|
+ // break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ throw new InvalidOperationException();
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return default;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
+ public sealed class ConsoleBotInteract : IInteractiveView
|
|
|
+ {
|
|
|
public void OnReceive(Response response)
|
|
|
- {
|
|
|
- Console.WriteLine(this.Name + ": " + response.Message);
|
|
|
+ {
|
|
|
+ Console.WriteLine("Bot: " + response.Message);
|
|
|
}
|
|
|
|
|
|
public string Accept()
|
|
@@ -115,7 +243,18 @@ namespace Yuuna
|
|
|
internal class EntryPoint
|
|
|
{
|
|
|
public static void Main(string[] args)
|
|
|
- {
|
|
|
+ {
|
|
|
+ var acc = new DefaultAcceptor();
|
|
|
+ Loop:
|
|
|
+ var rsp = acc.OnAccept(Console.ReadLine());
|
|
|
+ if(!rsp.Equals(default(Response)))
|
|
|
+ {
|
|
|
+ Console.WriteLine(rsp.Message);
|
|
|
+ goto Loop;
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
var canResponses = new Response[]
|
|
|
{
|
|
|
(Moods.Sad, "我不清楚你想做什麼 OvQ"),
|
|
@@ -130,7 +269,7 @@ namespace Yuuna
|
|
|
new Antonym("是", "否"),
|
|
|
};
|
|
|
|
|
|
- IInteractiveView interactor = new ConsoleBotInteract("悠");
|
|
|
+ IInteractiveView interactor = new ConsoleBotInteract( );
|
|
|
ITextSegmenter segmenter = new JiebaTextSegmenter();
|
|
|
IStrategy plan = new DefaultStrategy();
|
|
|
|
|
@@ -181,13 +320,8 @@ namespace Yuuna
|
|
|
|
|
|
text = interactor.Accept();
|
|
|
|
|
|
- //我: 開
|
|
|
- //悠: 你是想要開房門嗎?
|
|
|
- //我: 對
|
|
|
- //悠: 我不知道你想幹嘛 OHQ
|
|
|
foreach (var antonym in antonyms)
|
|
|
{
|
|
|
- Console.WriteLine("$" + antonym);
|
|
|
if (antonym.Judge(text, out var type))
|
|
|
{
|
|
|
if (type.Equals(Antonym.TypeKinds.Positive))
|
|
@@ -281,6 +415,8 @@ namespace Yuuna
|
|
|
}
|
|
|
|
|
|
case AlternativeStatus.Paradox:
|
|
|
+
|
|
|
+
|
|
|
break;
|
|
|
|
|
|
//case AlternativeStatus.NoModuleInstalled:
|