0x0001F36D преди 5 години
родител
ревизия
7124cb8c1c

+ 5 - 5
src/Yuuna.Contracts.Test/Fake.cs

@@ -49,7 +49,7 @@ namespace Yuuna.Contracts.Test
                         (Moods.Sad,  "可是門本來就是開的欸 QAQ"  ),
                     }
                     .RandomTakeOne();
-            }).OnIncomplete(s => throw new NotImplementedException());
+            });
 
             p.Build(g["close"], g["door"]).OnInvoke(score =>
             {
@@ -68,7 +68,7 @@ namespace Yuuna.Contracts.Test
                         (Moods.Sad,  "我不想動,因為本來就沒開過"  ),
                     }
                     .RandomTakeOne();
-            }).OnIncomplete(s => throw new NotImplementedException());
+            });
 
             p.Build(g["open"], g["light"]).OnInvoke(score =>
             {
@@ -81,10 +81,10 @@ namespace Yuuna.Contracts.Test
                 }
                 else
                     return (Moods.Sad, "可是燈本來就是開的欸 QAQ");
-            }).OnIncomplete(s => throw new NotImplementedException());
+            });
 
             p.Build(g["close"], g["light"]).OnInvoke(score =>
-            { 
+            {
                 Debug.WriteLine("燈的狀態是: " + (this._lightState ? "開著的" : "關著的"));
                 // 開燈 
                 if (this._lightState)
@@ -94,7 +94,7 @@ namespace Yuuna.Contracts.Test
                 }
                 else
                     return (Moods.Sad, "可是燈本來就是關的欸 QAQ");
-            }).OnIncomplete(s => throw new NotImplementedException());
+            });
 
         }
     }

+ 66 - 0
src/Yuuna.Contracts.Test/ViewService.cs

@@ -0,0 +1,66 @@
+
+namespace Yuuna.Contracts.Test
+{
+    using Microsoft.AspNetCore;
+    using Microsoft.AspNetCore.Builder;
+    using Microsoft.AspNetCore.Hosting;
+    using Microsoft.AspNetCore.Http;
+    using Microsoft.AspNetCore.Routing;
+    using Microsoft.Extensions.DependencyInjection;
+    using System;
+    using System.Collections.Concurrent;
+    using System.Collections.Generic;
+    using System.Text;
+    using System.Threading.Tasks;
+    using Yuuna.Contracts.Interaction;
+
+    public class ViewService : IInteractiveView2
+    {
+        private ConcurrentQueue<string> _taskQueue;
+
+        public ViewService()
+        {
+            this._taskQueue = new ConcurrentQueue<string>();
+
+            WebHost
+                .CreateDefaultBuilder()
+                .UseStartup<Startup>()
+                .Build()
+                .Run();
+        }
+        public Response Request(string text)
+        {
+            //接收到從客戶端來的文字
+            return null;
+        } 
+    }
+
+    public class Startup
+    {
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddRouting();
+        }
+        public void Configure(IApplicationBuilder app)
+        {
+            var defaultRouteHandler = new RouteHandler(context =>
+            {
+                var routeValues = context.GetRouteData().Values;
+                return context.Response.WriteAsync($"Route values: {string.Join(", ", routeValues)}");
+            });
+
+            var routeBuilder = new RouteBuilder(app, defaultRouteHandler);
+            routeBuilder.MapRoute("default", "{first:regex(^(default|home)$)}/{second?}");
+            
+            routeBuilder.MapPost("user/{text}", context => {
+                var text = context.GetRouteValue("text");
+                return context.Response.WriteAsync($"Create user. name: {name}");
+            });
+
+            var routes = routeBuilder.Build();
+            app.UseRouter(routes);
+        }
+
+
+    } 
+}

+ 20 - 0
src/Yuuna.Contracts/Interaction/IInteractiveView.cs

@@ -0,0 +1,20 @@
+// Author: Orlys
+// Github: https://github.com/Orlys
+
+namespace Yuuna.Contracts.Interaction
+{
+    using System;
+
+    public interface IInteractiveView
+    {
+        string Accept();
+
+        void OnReceive(Response response);
+    }
+
+
+    public interface IViewPipeline
+    {
+        Response OnRequest(string text); 
+    }
+}

+ 7 - 2
src/Yuuna.Contracts/Optimization/DefaultStrategy.cs

@@ -68,8 +68,8 @@ namespace Yuuna.Contracts.Optimization
             var bestSelect = default(List<Match>);
             foreach (var s in sta)
             {
-                var y =  Math.Tanh(Math.Pow(Math.E, (s.Value.Count) / (double)-(matches.Count *  s.Key)));
-
+                //var y =  Math.Tanh(Math.Pow(Math.E, (s.Value.Count) / (double)-(matches.Count *  s.Key)));
+               var y = Quantize(s.Value.Count, matches.Count, s.Key);
                 Debug.WriteLine((s.Key, y));
                 if (y > weight)
                 {
@@ -82,6 +82,11 @@ namespace Yuuna.Contracts.Optimization
             return a;
         }
 
+        private static double Quantize(int elementCount, int categorizedCount, int matchedCount)
+        {
+            return Math.Tanh(Math.Pow(Math.E, (elementCount) / (double)-(categorizedCount * matchedCount)));
+        }
+
         /// <summary>
         /// 評估 <paramref name="pattern"/> 與 <paramref name="feed"/> 的符合程度並返回一個 <see cref="Match"/> 物件。
         /// </summary>

+ 4 - 4
src/Yuuna.Contracts/Patterns/IIncompleteBuilder.cs

@@ -2,8 +2,8 @@
 // Github: https://github.com/Orlys
 namespace Yuuna.Contracts.Patterns
 {
-    public interface IIncompleteBuilder
-    {
-        void OnIncomplete(Incomplete incomplete);
-    }
+    //public interface IIncompleteBuilder
+    //{
+    //    void OnIncomplete(Incomplete incomplete);
+    //}
 }

+ 2 - 1
src/Yuuna.Contracts/Patterns/IInvokeBuilder.cs

@@ -4,6 +4,7 @@ namespace Yuuna.Contracts.Patterns
 {
     public interface IInvokeBuilder
     {
-        IIncompleteBuilder OnInvoke(Invoke invoke);
+        void OnInvoke(Invoke invoke);
+        //IIncompleteBuilder OnInvoke(Invoke invoke);
     }
 }

+ 1 - 1
src/Yuuna.Contracts/Patterns/Internal/Bag.cs

@@ -5,7 +5,7 @@ namespace Yuuna.Contracts.Patterns
 {
     public struct Bag
     {
-        public Incomplete Incomplete;
+        //public Incomplete Incomplete;
         public Invoke Invoke;
         public IPattern Pattern;
     }

+ 9 - 9
src/Yuuna.Contracts/Patterns/Internal/IncompleteBuilder.cs

@@ -7,13 +7,13 @@ namespace Yuuna.Contracts.Patterns
 
     using Yuuna.Common.Artisan.Cascade;
 
-    internal sealed class IncompleteBuilder : Output<Incomplete>, IIncompleteBuilder
-    {
-        public void OnIncomplete(Incomplete incomplete)
-        {
-            if (incomplete is null)
-                throw new ArgumentNullException(nameof(incomplete));
-            this.MoveNext(incomplete);
-        }
-    }
+    //internal sealed class IncompleteBuilder : Output<Incomplete>, IIncompleteBuilder
+    //{
+    //    public void OnIncomplete(Incomplete incomplete)
+    //    {
+    //        if (incomplete is null)
+    //            throw new ArgumentNullException(nameof(incomplete));
+    //        this.MoveNext(incomplete);
+    //    }
+    //}
 }

+ 14 - 3
src/Yuuna.Contracts/Patterns/Internal/InvokeBuilder.cs

@@ -7,13 +7,24 @@ namespace Yuuna.Contracts.Patterns
 
     using Yuuna.Common.Artisan.Cascade;
 
-    internal sealed class InvokeBuilder : Pipeline<IncompleteBuilder, Invoke>, IInvokeBuilder
+    //internal sealed class InvokeBuilder : Pipeline<IncompleteBuilder, Invoke>, IInvokeBuilder
+    //{
+    //    public IIncompleteBuilder OnInvoke(Invoke invoke)
+    //    {
+    //        if (invoke is null)
+    //            throw new ArgumentNullException(nameof(invoke));
+    //        return this.MoveNext(invoke);
+    //    }
+    //}
+
+    internal sealed class InvokeBuilder : Output<Invoke>, IInvokeBuilder
     {
-        public IIncompleteBuilder OnInvoke(Invoke invoke)
+        public void OnInvoke(Invoke invoke)
         {
             if (invoke is null)
                 throw new ArgumentNullException(nameof(invoke));
-            return this.MoveNext(invoke);
+            this.MoveNext(invoke);
+            //return this.MoveNext(invoke);
         }
     }
 }

+ 1 - 2
src/Yuuna.Contracts/Patterns/Internal/PatternFactory.cs

@@ -51,10 +51,9 @@ namespace Yuuna.Contracts.Patterns
             {
                 Pattern = session.Dequeue() as IPattern,
                 Invoke = session.Dequeue() as Invoke,
-                Incomplete = session.Dequeue() as Incomplete,
+                //Incomplete = session.Dequeue() as Incomplete,
             };
 
-            Debug.WriteLine("#" + string.Join("::", ge.Pattern.SequentialKeys));
             this._list.TryAdd(ge.Pattern, ge);
         }
     }

+ 158 - 22
src/Yuuna/EntryPoint.cs

@@ -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: