<commit_before>﻿using Cottle.Builtins;
using Cottle.Documents;
using Cottle.Functions;
using Cottle.Settings;
using Cottle.Stores;
using Cottle.Values;
using Eddi;
using EddiDataDefinitions;
using EddiDataProviderService;
using EddiSpeechService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Utilities;

namespace EddiSpeechResponder
{
    public class ScriptResolver
    {
        private Dictionary<string, Script> scripts = new Dictionary<string, Script>();
        private Random random;
        private CustomSetting setting;

        public static object Instance { get; set; }

        public ScriptResolver(Dictionary<string, Script> scripts)
        {
            random = new Random();
            if (scripts != null) { this.scripts = scripts; }
            setting = new CustomSetting();
            setting.Trimmer = BuiltinTrimmers.CollapseBlankCharacters;
        }

        public string resolve(string name, Dictionary<string, Cottle.Value> vars, bool storeresult = true)
        {
            return resolve(name, buildStore(vars), storeresult);
        }

        public int priority(string name)
        {
            Script script;
            scripts.TryGetValue(name, out script);
            return (script == null ? 5 : script.Priority);
        }

        public string resolve(string name, BuiltinStore store, bool storeresult = true)
        {
            Logging.Debug("Resolving script " + name);
            Script script;
            scripts.TryGetValue(name, out script);
            if (script == null || script.Value == null)
            {
                Logging.Debug("No script");
                return null;
            }
            Logging.Debug("Found script");
            if (script.Enabled == false)
            {
                Logging.Debug("Script disabled");
                return null;
            }

            return resolveScript(script.Value, store, storeresult);
        }

        /// <summary>
        /// Resolve a script with an existing store
        /// </summary>
        public string resolveScript(string script, BuiltinStore store, bool storeresult = true)
        {
            try
            {
                // Before we start, we remove the context.  This means that scripts without context still work as expected
                EDDI.Instance.State["eddi_context_last_subject"] = null;

                var document = new SimpleDocument(script, setting);
                var result = document.Render(store);
                // Tidy up the output script
                result = Regex.Replace(result, " +", " ").Replace(" ,", ",").Replace(" .", ".").Trim();
                Logging.Debug("Turned script " + script + " in to speech " + result);
                result = result.Trim() == "" ? null : result.Trim();

                if (storeresult && result != null)
                {
                    Logging.Info("Last speech is " + result);
                    EDDI.Instance.State["eddi_context_last_speech"] = result;
                    if (EDDI.Instance.State["eddi_context_last_subject"] != null)
                    {
                        EDDI.Instance.State["edd_context_last_speech_" + EDDI.Instance.State["eddi_context_subject"]] = result;
                    }
                }

                return result;
            }
            catch (Exception e)
            {
                Logging.Warn("Failed to resolve script: " + e.ToString());
                return "There is a problem with the script: " + e.Message.Replace("'", "");
            }
        }

        /// <summary>
        /// Build a store from a list of variables
        /// </summary>
        private BuiltinStore buildStore(Dictionary<string, Cottle.Value> vars)
        {
            BuiltinStore store = new BuiltinStore();

            // Function to call another script
            store["F"] = new NativeFunction((values) =>
            {
                return new ScriptResolver(scripts).resolve(values[0].AsString, store, false);
            }, 1);

            // Translation functions
            store["P"] = new NativeFunction((values) =>
            {
                string val = values[0].AsString;
                string translation = val;
                if (translation == val)<commit_msg>Various fixes for state and speech responder interaction<commit_after>﻿using Cottle.Builtins;
using Cottle.Documents;
using Cottle.Functions;
using Cottle.Settings;
using Cottle.Stores;
using Cottle.Values;
using Eddi;
using EddiDataDefinitions;
using EddiDataProviderService;
using EddiSpeechService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Utilities;

namespace EddiSpeechResponder
{
    public class ScriptResolver
    {
        private Dictionary<string, Script> scripts = new Dictionary<string, Script>();
        private Random random;
        private CustomSetting setting;

        public static object Instance { get; set; }

        public ScriptResolver(Dictionary<string, Script> scripts)
        {
            random = new Random();
            if (scripts != null) { this.scripts = scripts; }
            setting = new CustomSetting();
            setting.Trimmer = BuiltinTrimmers.CollapseBlankCharacters;
        }

        public string resolve(string name, Dictionary<string, Cottle.Value> vars, bool master = true)
        {
            return resolve(name, buildStore(vars), master);
        }

        public int priority(string name)
        {
            Script script;
            scripts.TryGetValue(name, out script);
            return (script == null ? 5 : script.Priority);
        }

        public string resolve(string name, BuiltinStore store, bool master = true)
        {
            Logging.Debug("Resolving script " + name);
            Script script;
            scripts.TryGetValue(name, out script);
            if (script == null || script.Value == null)
            {
                Logging.Debug("No script");
                return null;
            }
            Logging.Debug("Found script");
            if (script.Enabled == false)
            {
                Logging.Debug("Script disabled");
                return null;
            }

            return resolveScript(script.Value, store, master);
        }

        /// <summary>
        /// Resolve a script with an existing store
        /// </summary>
        public string resolveScript(string script, BuiltinStore store, bool master = true)
        {
            try
            {
                // Before we start, we remove the context for master scripts.
                // This means that scripts without context still work as expected
                if (master)
                {
                    EDDI.Instance.State["eddi_context_last_subject"] = null;
                    EDDI.Instance.State["eddi_context_last_action"] = null;
                }

                var document = new SimpleDocument(script, setting);
                var result = document.Render(store);
                // Tidy up the output script
                result = Regex.Replace(result, " +", " ").Replace(" ,", ",").Replace(" .", ".").Trim();
                Logging.Debug("Turned script " + script + " in to speech " + result);
                result = result.Trim() == "" ? null : result.Trim();

                if (master && result != null)
                {
                    string stored = result;
                    // Remove any leading pause
                    if (stored.StartsWith("<break"))
                    {
                        string pattern = "^<break[^>]*>";
                        string replacement = "";
                        Regex rgx = new Regex(pattern);
                        stored = rgx.Replace(stored, replacement);
                    }

                    EDDI.Instance.State["eddi_context_last_speech"] = stored;
                    object lastSubject;
                    if (EDDI.Instance.State.TryGetValue("eddi_context_last_subject", out lastSubject))
                    {
                        string csLastSubject = ((string)EDDI.Instance.State["eddi_context_last_subject"]).ToLowerInvariant().Replace(" ", "_");
                        EDDI.Instance.State["eddi_context_last_speech_" + csLastSubject] = stored;
                    }
                }

                return result;
            }
            catch (Exception e)
            {
                Logging.Warn("Failed to resolve script: " + e.ToString());
                return "There is a problem with the script: " + e.Message.Replace("'", "");
            }
        }

        /// <summary>
        /// Build a store from a list of variables
        /// </summary>
        private BuiltinStore buildStore(Dictionary<string, Cottle.Value> vars)
        {
            BuiltinStore store = new BuiltinStore();

            // Function to call another script
            store["F"] = new NativeFunction((values) =>
            {
                return new ScriptResolver(scripts).resolve(values[0].AsString, store, false);
            }, 1);

            // Translation functions
            store["P"] = new NativeFunction((values) =>
            {
                string val = values[0].AsString;
                string translation = val;
                if (translation == val)
{'fraction_non_alphanumeric': 0.1006804167552626, 'fraction_numerical': 0.0008505209440782479, 'mean_word_length': 1.664117813650524, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4419117', 'n_tokens_mistral': 2360, 'n_tokens_neox': 2212, 'n_words': 610}