Eliza C# port

fukurou

the supreme coder
ADMIN
C#:
public class LimUniqueResponder
{
    private List<string> responses;
    private UniqueRandomGenerator urg = new UniqueRandomGenerator(0);
    private readonly int lim;

    // Constructor
    public LimUniqueResponder(int lim)
    {
        responses = new List<string>();
        this.lim = lim;
    }

    // Method to get a response
    public string GetAResponse()
    {
        if (responses.Count == 0)
        {
            return "";
        }
        return responses[urg.GetUniqueRandom()];
    }

    // Method to check if responses contain a string
    public bool ResponsesContainsStr(string item)
    {
        return responses.Contains(item);
    }

    // Method to check if a string contains any response
    public bool StrContainsResponse(string item)
    {
        foreach (string response in responses)
        {
            if (string.IsNullOrEmpty(response))
            {
                continue;
            }
            if (item.Contains(response))
            {
                return true;
            }
        }
        return false;
    }

    // Method to add a response
    public void AddResponse(string s1)
    {
        if (this.responses.Count > lim - 1)
        {
            responses.RemoveAt(0);
        }
        if (!responses.Contains(s1))
        {
            responses.Add(s1);
            urg = new UniqueRandomGenerator(responses.Count);
        }
    }

    // Method to add multiple responses
    public void AddResponses(params string[] replies)
    {
        foreach (string value in replies)
        {
            AddResponse(value);
        }
    }

    // Method to get a savable string
    public string GetSavableStr()
    {
        return string.Join("_", responses);
    }

    // Method to get the last item
    public string GetLastItem()
    {
        if (responses.Count == 0)
        {
            return "";
        }
        return responses[responses.Count - 1];
    }
}
 

fukurou

the supreme coder
ADMIN
C#:
public class EventChatV2
{
    private readonly Dictionary<string, LimUniqueResponder> dic = new Dictionary<string, LimUniqueResponder>();
    private readonly HashSet<string> modifiedKeys = new HashSet<string>();
    private readonly int lim;

    // Constructor
    public EventChatV2(int lim)
    {
        this.lim = lim;
    }

    // Get modified keys
    public HashSet<string> GetModifiedKeys()
    {
        return modifiedKeys;
    }

    // Check if a key exists
    public bool KeyExists(string key)
    {
        return modifiedKeys.Contains(key);
    }

    // Add items
    public void AddItems(LimUniqueResponder ur, params string[] args)
    {
        foreach (var arg in args)
        {
            dic[arg] = ur;
        }
    }

    // Add from database
    public void AddFromDB(string key, string value)
    {
        if (string.IsNullOrEmpty(value) || value == "null")
        {
            return;
        }
        var tool1 = new AXStringSplit();
        var values = tool1.Split(value);
        if (!dic.ContainsKey(key))
        {
            dic[key] = new LimUniqueResponder(lim);
        }
        foreach (var item in values)
        {
            dic[key].AddResponse(item);
        }
    }

    // Add key-value pair
    public void AddKeyValue(string key, string value)
    {
        modifiedKeys.Add(key);
        if (dic.ContainsKey(key))
        {
            dic[key].AddResponse(value);
        }
        else
        {
            dic[key] = new LimUniqueResponder(lim);
            dic[key].AddResponse(value);
        }
    }

    // Add key-values from a list of AXKeyValuePair
    public void AddKeyValues(List<AXKeyValuePair> elizaResults)
    {
        foreach (var pair in elizaResults)
        {
            AddKeyValue(pair.GetKey(), pair.GetValue());
        }
    }

    // Get response
    public string Response(string in1)
    {
        return dic.ContainsKey(in1) ? dic[in1].GetAResponse() : "";
    }

    // Get latest response
    public string ResponseLatest(string in1)
    {
        return dic.ContainsKey(in1) ? dic[in1].GetLastItem() : "";
    }

    // Get save string
    public string GetSaveStr(string key)
    {
        return dic[key].GetSavableStr();
    }
}
 

fukurou

the supreme coder
ADMIN
C#:
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class ElizaDeducer
{
    // This class populates a special chat dictionary based on the matches added via its AddPhraseMatcher function.
    // See subclass ElizaDeducerInitializer for example:
    // var ed = new ElizaDeducerInitializer(2); // 2 = limit of replies per input

    public List<PhraseMatcher> Babble2 { get; private set; }
    private readonly Dictionary<string, List<PhraseMatcher>> patternIndex;
    private readonly Dictionary<string, List<AXKeyValuePair>> responseCache;
    private readonly EventChatV2 ec2; // Chat dictionary, use getter for access. Hardcoded replies can also be added.

    public ElizaDeducer(int lim)
    {
        Babble2 = new List<PhraseMatcher>();
        patternIndex = new Dictionary<string, List<PhraseMatcher>>();
        responseCache = new Dictionary<string, List<AXKeyValuePair>>();
        ec2 = new EventChatV2(lim);
    }

    public EventChatV2 GetEc2()
    {
        return ec2;
    }

    public void Learn(string msg)
    {
        // Populate EventChat dictionary
        // Check cache first
        if (responseCache.ContainsKey(msg))
        {
            ec2.AddKeyValues(new List<AXKeyValuePair>(responseCache[msg]));
        }

        // Search for matching patterns
        List<PhraseMatcher> potentialMatchers = GetPotentialMatchers(msg);
        foreach (var pm in potentialMatchers)
        {
            if (pm.Matches(msg))
            {
                List<AXKeyValuePair> response = pm.Respond(msg);
                responseCache[msg] = response;
                ec2.AddKeyValues(response);
            }
        }
    }

    public bool LearnedBool(string msg)
    {
        // Same as Learn method but returns True if it learned new replies
        bool learned = false;

        // Populate EventChat dictionary
        // Check cache first
        if (responseCache.ContainsKey(msg))
        {
            ec2.AddKeyValues(new List<AXKeyValuePair>(responseCache[msg]));
            learned = true;
        }

        // Search for matching patterns
        List<PhraseMatcher> potentialMatchers = GetPotentialMatchers(msg);
        foreach (var pm in potentialMatchers)
        {
            if (pm.Matches(msg))
            {
                List<AXKeyValuePair> response = pm.Respond(msg);
                responseCache[msg] = response;
                ec2.AddKeyValues(response);
                learned = true;
            }
        }

        return learned;
    }

    public string Respond(string str1)
    {
        return ec2.Response(str1);
    }

    public string RespondLatest(string str1)
    {
        // Get most recent reply/data
        return ec2.ResponseLatest(str1);
    }

    private List<PhraseMatcher> GetPotentialMatchers(string msg)
    {
        var potentialMatchers = new List<PhraseMatcher>();
        foreach (var key in patternIndex.Keys)
        {
            if (msg.Contains(key))
            {
                potentialMatchers.AddRange(patternIndex[key]);
            }
        }
        return potentialMatchers;
    }

    public void AddPhraseMatcher(string pattern, params string[] kvPairs)
    {
        var kvs = new List<AXKeyValuePair>();
        for (int i = 0; i < kvPairs.Length; i += 2)
        {
            kvs.Add(new AXKeyValuePair(kvPairs[i], kvPairs[i + 1]));
        }
        var matcher = new PhraseMatcher(pattern, kvs);
        Babble2.Add(matcher);
        IndexPattern(pattern, matcher);
    }

    private void IndexPattern(string pattern, PhraseMatcher matcher)
    {
        foreach (var word in pattern.Split(' '))
        {
            if (!patternIndex.ContainsKey(word))
            {
                patternIndex[word] = new List<PhraseMatcher>();
            }
            patternIndex[word].Add(matcher);
        }
    }

    public class PhraseMatcher
    {
        public Regex Matcher { get; private set; }
        public List<AXKeyValuePair> Responses { get; private set; }

        public PhraseMatcher(string matcher, List<AXKeyValuePair> responses)
        {
            Matcher = new Regex(matcher);
            Responses = responses;
        }

        public bool Matches(string str)
        {
            return Matcher.IsMatch(str);
        }

        public List<AXKeyValuePair> Respond(string str)
        {
            Match m = Matcher.Match(str);
            var result = new List<AXKeyValuePair>();
            if (m.Success)
            {
                int tmp = m.Groups.Count - 1; // GroupCount in Java is equivalent to Groups.Count - 1 in .NET
                foreach (var kv in Responses)
                {
                    var tempKV = new AXKeyValuePair(kv.GetKey(), kv.GetValue());
                    for (int i = 0; i < tmp; i++)
                    {
                        string s = m.Groups[i + 1].Value;
                        tempKV.SetKey(tempKV.GetKey().Replace("{" + i + "}", s).ToLower());
                        tempKV.SetValue(tempKV.GetValue().Replace("{" + i + "}", s).ToLower());
                    }
                    result.Add(tempKV);
                }
            }
            return result;
        }
    }
}
 

fukurou

the supreme coder
ADMIN
C#:
using System;

public class ElizaDeducerInitializer : ElizaDeducer
{
    // Constructor
    public ElizaDeducerInitializer(int lim) : base(lim)
    {
        // Recommended lim = 5; it's the limit of responses per key in the EventChat dictionary.
        // The purpose of the lim is to make saving and loading data easier.
        InitializeBabble2();
    }

    // Initialize the babble2 list with predefined phrase matchers
    private void InitializeBabble2()
    {
        AddPhraseMatcher(
            "(.*) is (.*)",
            "what is {0}", "{0} is {1}",
            "explain {0}", "{0} is {1}"
        );

        AddPhraseMatcher(
            "if (.*) or (.*) than (.*)",
            "{0}", "{2}",
            "{1}", "{2}"
        );

        AddPhraseMatcher(
            "if (.*) and (.*) than (.*)",
            "{0}", "{1}"
        );

        AddPhraseMatcher(
            "(.*) because (.*)",
            "{1}", "i guess {0}"
        );
    }
}
 

fukurou

the supreme coder
ADMIN
C#:
public class ElizaDBWrapper
{
    // This (function wrapper) class adds save/load functionality to the ElizaDeducer Object.
    // Example usage:
    // var ed = new ElizaDeducerInitializer(2);
    // ed.GetEc2().AddFromDB("test", "one_two_three"); // Manual load for testing
    // var k = new Kokoro(new AbsDictionaryDB()); // Use skill's kokoro attribute
    // var ew = new ElizaDBWrapper();
    // Console.WriteLine(ew.Respond("test", ed.GetEc2(), k)); // Get reply for input, tries loading reply from DB
    // Console.WriteLine(ew.Respond("test", ed.GetEc2(), k)); // Doesn't try DB load on second run
    // ed.Learn("a is b"); // Learn only after respond
    // ew.SleepNSave(ed.GetEc2(), k); // Save when bot is sleeping, not on every skill input method visit

    private readonly HashSet<string> modifiedKeys = new HashSet<string>();

    public string Respond(string in1, EventChatV2 ec, Kokoro kokoro)
    {
        if (modifiedKeys.Contains(in1))
        {
            return ec.Response(in1);
        }
        modifiedKeys.Add(in1);
        // Load
        ec.AddFromDB(in1, kokoro.grimoireMemento.SimpleLoad(in1));
        return ec.Response(in1);
    }

    public string RespondLatest(string in1, EventChatV2 ec, Kokoro kokoro)
    {
        if (modifiedKeys.Contains(in1))
        {
            return ec.ResponseLatest(in1);
        }
        modifiedKeys.Add(in1);
        // Load and get latest reply for input
        ec.AddFromDB(in1, kokoro.grimoireMemento.SimpleLoad(in1));
        return ec.ResponseLatest(in1);
    }

    public void SleepNSave(EventChatV2 ecv2, Kokoro kokoro)
    {
        foreach (var element in ecv2.GetModifiedKeys())
        {
            kokoro.grimoireMemento.SimpleSave(element, ecv2.GetSaveStr(element));
        }
    }
}
 
Top