<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Speech.Recognition;
using System.Text;
using System.Threading.Tasks;

namespace AudioExtensions
{
    public class VoiceRecognitionWindows : VoiceRecognition
    {
        public float Confidence { get; set; } = 0.96F;

        public event SpeechRecognised SpeechRecognised;
        public bool IsOpen { get { return engine != null; } }

        private SpeechRecognitionEngine engine;
        private System.Globalization.CultureInfo ct;

        public bool Open(System.Globalization.CultureInfo ctp)
        {
            ct = ctp;

            if (engine != null)
                engine.Dispose();

            engine = new SpeechRecognitionEngine(ct);

            try
            {
                engine.SetInputToDefaultAudioDevice(); // crashes if no default device..
            }
            catch
            {
                engine = null;
                return false;
            }

            engine.SpeechRecognized += Engine_SpeechRecognized;
            engine.SpeechHypothesized += Engine_SpeechHypothesized;
            engine.SpeechRecognitionRejected += Engine_SpeechRecognitionRejected;

            System.Diagnostics.Debug.WriteLine("Engine {0}", engine.RecognizerInfo.Description);
            foreach (var x in engine.RecognizerInfo.AdditionalInfo)
                System.Diagnostics.Debug.WriteLine(".. " + x.Key + "=" + x.Value);

            return true;
        }

        public void Close()
        {
            if (engine != null )
            {
                Stop(true);
                System.Diagnostics.Debug.WriteLine("Closing");
                engine.SpeechRecognized -= Engine_SpeechRecognized;
                engine.Dispose();
                engine = null;
            }
        }

        public bool Start()
        {
            if (engine != null && engine.Grammars.Count > 0 && engine.AudioState == AudioState.Stopped)
            {
                System.Diagnostics.Debug.WriteLine("Starting with {0} Babble {1} EndSel {2} EndSelAmb {3} Initial {4} MaxAlt {5}", engine.Grammars.Count, engine.BabbleTimeout, engine.EndSilenceTimeout, engine.EndSilenceTimeoutAmbiguous, engine.InitialSilenceTimeout, engine.MaxAlternates);
                engine.RecognizeAsync(RecognizeMode.Multiple);        // got a grammar, start..
                return true;
            }
            else
                return false;
        }

        public void Stop(bool waitfor)
        {
            if (engine != null && engine.AudioState != AudioState.Stopped)
            {
                System.Diagnostics.Debug.WriteLine(Environment.TickCount + " Voice Recognition Stopping");
                engine.UnloadAllGrammars();
                engine.RecognizeAsyncCancel();

                if (waitfor)
                {
                    int max = 100;
                    while (max-- > 0 && engine.AudioState != AudioState.Stopped)
                        System.Threading.Thread.Sleep(10);
                    if (max <= 0)
                        ExtendedControls.MessageBoxTheme.Show("Voice recon did not stop", "Voice Audio Problem");
                }

                System.Diagnostics.Debug.WriteLine(Environment.TickCount + "Voice Recognition Stopped");
            }
        }

        public bool AddRange(List<string> s)
        {
            foreach (string x in s)
            {
                if (x.Length>0 && !Add(x))
                    return false;
            }

            return true;
        }

        public bool Add(string s)       // S is in voice prompt format with [] and | and ; seperating
        {
           // System.Diagnostics.Debug.WriteLine("Engine State" + engine?.AudioState);
            if (engine != null && engine.AudioState == AudioState.Stopped && s.Length>0)
            {
                GrammarBuilder builder = new GrammarBuilder();

                string[] b = s.Split(';');
                foreach( string p in b )
                {
                    if (p.Length > 0)
                    {
                        System.Diagnostics.Debug.Write(p);
                        builder.Append(p);
                    }

                }

                //BaseUtils.StringCombinations sb = new BaseUtils.StringCombinations();

                //foreach (List<List<string>> groups in sb.ParseGroup(s))     // for each semicolon group, give me the word combinations
                //{
                //    foreach (List<string> wordlist in groups)     // for each vertical word list
                //    {
                //        if (wordlist.Count == 1)      // single entry, must be simple, just add
                //        {
                //            builder.Append(wordlist[0]);
                //            System.Diagnostics.Debug.Write(wordlist[0]);
                //        }
                //        else
                //        {
                //            List<GrammarBuilder> sub = new List<GrammarBuilder>();

                //            int emptycount = (from x in wordlist where x.Length == 0 select x).Count();   // is there any empty ones indicating optionality

                //            foreach (string o in wordlist)
                //            {
                //                if (o.Length > 0)
                //                {
                //                    sub.Add(new GrammarBuilder());
                //                    sub.Last().Append(o, (emptycount > 0) ? 0 : 1, 1);      // indicate number of times, either 1:1 or 0,1 if we have an optional entry
                //                    System.Diagnostics.Debug.Write((wordlist.IndexOf(o) > 0 ? "|" : "") + o);
                //                }
                //                else
                //                    System.Diagnostics.Debug.Write("|[]");
                //            }

                //            Choices c = new Choices(sub.ToArray());
                //            builder.Append(c);
                //        }

                //        System.Diagnostics.Debug.Write(" ");
                //    }
                //    System.Diagnostics.Debug.WriteLine("");
                //}


                builder.Culture = ct;

                Grammar gr = new Grammar(builder);
                engine.LoadGrammar(gr);

                return true;
            }
            else
                return false;
        }


        private void Engine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            var x = e.Result;
            DumpInfo("Recognised", e.Result);
            System.Diagnostics.Debug.WriteLine("Confidence {0} vs threshold {1}", e.Result.Confidence, Confidence);
            if (e.Result.Confidence >= Confidence)
                SpeechRecognised?.Invoke(e.Result.Text, e.Result.Confidence);
        }

        private void Engine_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            DumpInfo("Rejected", e.Result);
        }

        private void Engine_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            DumpInfo("Hypothesised", e.Result);
        }


        void DumpInfo(string t, RecognitionResult r)
        {
            System.Diagnostics.Debug.WriteLine(t + " " + r.Text + " " + r.Confidence.ToString("#.00"));
            foreach (RecognizedPhrase p in r.Alternates)
                System.Diagnostics.Debug.WriteLine("... alt " + p.Text + p.Confidence.ToString("#.00"));

            foreach (KeyValuePair<String, SemanticValue> child in r.Semantics)
            {
                System.Diagnostics.Debug.WriteLine("    The {0} city is {1}",
                  child.Key, child.Value.Value ?? "null");<commit_msg>Improved debug output<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Speech.Recognition;
using System.Text;
using System.Threading.Tasks;

namespace AudioExtensions
{
    public class VoiceRecognitionWindows : VoiceRecognition
    {
        public float Confidence { get; set; } = 0.96F;

        public event SpeechRecognised SpeechRecognised;
        public bool IsOpen { get { return engine != null; } }

        private SpeechRecognitionEngine engine;
        private System.Globalization.CultureInfo ct;

        public bool Open(System.Globalization.CultureInfo ctp)
        {
            ct = ctp;

            if (engine != null)
                engine.Dispose();

            engine = new SpeechRecognitionEngine(ct);

            try
            {
                engine.SetInputToDefaultAudioDevice(); // crashes if no default device..
            }
            catch
            {
                engine = null;
                return false;
            }

            engine.SpeechRecognized += Engine_SpeechRecognized;
            engine.SpeechHypothesized += Engine_SpeechHypothesized;
            engine.SpeechRecognitionRejected += Engine_SpeechRecognitionRejected;

            System.Diagnostics.Debug.WriteLine("Engine {0}", engine.RecognizerInfo.Description);
            foreach (var x in engine.RecognizerInfo.AdditionalInfo)
                System.Diagnostics.Debug.WriteLine(".. " + x.Key + "=" + x.Value);

            return true;
        }

        public void Close()
        {
            if (engine != null )
            {
                Stop(true);
                System.Diagnostics.Debug.WriteLine("Closing");
                engine.SpeechRecognized -= Engine_SpeechRecognized;
                engine.Dispose();
                engine = null;
            }
        }

        public bool Start()
        {
            if (engine != null && engine.Grammars.Count > 0 && engine.AudioState == AudioState.Stopped)
            {
                System.Diagnostics.Debug.WriteLine("Starting with {0} Babble {1} EndSel {2} EndSelAmb {3} Initial {4} MaxAlt {5}", engine.Grammars.Count, engine.BabbleTimeout, engine.EndSilenceTimeout, engine.EndSilenceTimeoutAmbiguous, engine.InitialSilenceTimeout, engine.MaxAlternates);
                engine.RecognizeAsync(RecognizeMode.Multiple);        // got a grammar, start..
                return true;
            }
            else
                return false;
        }

        public void Stop(bool waitfor)
        {
            if (engine != null && engine.AudioState != AudioState.Stopped)
            {
                System.Diagnostics.Debug.WriteLine(Environment.TickCount + " Voice Recognition Stopping");
                engine.UnloadAllGrammars();
                engine.RecognizeAsyncCancel();

                if (waitfor)
                {
                    int max = 100;
                    while (max-- > 0 && engine.AudioState != AudioState.Stopped)
                        System.Threading.Thread.Sleep(10);
                    if (max <= 0)
                        ExtendedControls.MessageBoxTheme.Show("Voice recon did not stop", "Voice Audio Problem");
                }

                System.Diagnostics.Debug.WriteLine(Environment.TickCount + "Voice Recognition Stopped");
            }
        }

        public bool AddRange(List<string> s)
        {
            foreach (string x in s)
            {
                if (x.Length>0 && !Add(x))
                    return false;
            }

            return true;
        }

        public bool Add(string s)       // S is in voice prompt format with [] and | and ; seperating
        {
           // System.Diagnostics.Debug.WriteLine("Engine State" + engine?.AudioState);
            if (engine != null && engine.AudioState == AudioState.Stopped && s.Length>0)
            {
                GrammarBuilder builder = new GrammarBuilder();

                string[] b = s.Split(';');
                foreach( string p in b )
                {
                    if (p.Length > 0)
                    {
                        System.Diagnostics.Debug.Write(p + ". ");
                        builder.Append(p);
                    }

                }

                //BaseUtils.StringCombinations sb = new BaseUtils.StringCombinations();

                //foreach (List<List<string>> groups in sb.ParseGroup(s))     // for each semicolon group, give me the word combinations
                //{
                //    foreach (List<string> wordlist in groups)     // for each vertical word list
                //    {
                //        if (wordlist.Count == 1)      // single entry, must be simple, just add
                //        {
                //            builder.Append(wordlist[0]);
                //            System.Diagnostics.Debug.Write(wordlist[0]);
                //        }
                //        else
                //        {
                //            List<GrammarBuilder> sub = new List<GrammarBuilder>();

                //            int emptycount = (from x in wordlist where x.Length == 0 select x).Count();   // is there any empty ones indicating optionality

                //            foreach (string o in wordlist)
                //            {
                //                if (o.Length > 0)
                //                {
                //                    sub.Add(new GrammarBuilder());
                //                    sub.Last().Append(o, (emptycount > 0) ? 0 : 1, 1);      // indicate number of times, either 1:1 or 0,1 if we have an optional entry
                //                    System.Diagnostics.Debug.Write((wordlist.IndexOf(o) > 0 ? "|" : "") + o);
                //                }
                //                else
                //                    System.Diagnostics.Debug.Write("|[]");
                //            }

                //            Choices c = new Choices(sub.ToArray());
                //            builder.Append(c);
                //        }

                //        System.Diagnostics.Debug.Write(" ");
                //    }
                //    System.Diagnostics.Debug.WriteLine("");
                //}


                builder.Culture = ct;

                Grammar gr = new Grammar(builder);
                engine.LoadGrammar(gr);

                return true;
            }
            else
                return false;
        }


        private void Engine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            var x = e.Result;
            DumpInfo("Recognised", e.Result);
            System.Diagnostics.Debug.WriteLine("Confidence {0} vs threshold {1} for {2}", e.Result.Confidence, Confidence, e.Result.Text);
            if (e.Result.Confidence >= Confidence)
                SpeechRecognised?.Invoke(e.Result.Text, e.Result.Confidence);
        }

        private void Engine_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            DumpInfo("Rejected", e.Result);
        }

        private void Engine_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            DumpInfo("Hypothesised", e.Result);
        }


        void DumpInfo(string t, RecognitionResult r)
        {
            System.Diagnostics.Debug.WriteLine(t + " " + r.Text + " " + r.Confidence.ToString("#.00"));
            foreach (RecognizedPhrase p in r.Alternates)
                System.Diagnostics.Debug.WriteLine("... alt " + p.Text + p.Confidence.ToString("#.00"));

            foreach (KeyValuePair<String, SemanticValue> child in r.Semantics)
            {
                System.Diagnostics.Debug.WriteLine("    The {0} city is {1}",
                  child.Key, child.Value.Value ?? "null");
{'fraction_non_alphanumeric': 0.10172634271099744, 'fraction_numerical': 0.005562659846547314, 'mean_word_length': 1.3316935002981514, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '949230', 'n_tokens_mistral': 4119, 'n_tokens_neox': 3741, 'n_words': 848}