From d01fa376bd8121d0d14a242fb073643a93830080 Mon Sep 17 00:00:00 2001 From: Paci <89483951+PaciStardust@users.noreply.github.com> Date: Fri, 24 Mar 2023 22:16:28 +0100 Subject: [PATCH 1/8] Initial Test Commit --- OscMultitool/Config.cs | 612 +----------------- OscMultitool/Hoscy.csproj | 10 +- OscMultitool/Models/ApiPresetModel.cs | 75 +++ OscMultitool/Models/ConfigModels.cs | 349 ++++++++++ OscMultitool/Models/CounterModel.cs | 46 ++ OscMultitool/Models/OscRoutingFilterModel.cs | 32 + OscMultitool/Models/RegexModels.cs | 150 +++++ OscMultitool/Services/Api/ApiClient.cs | 7 +- .../Services/OscControl/OscDataHandler.cs | 1 - .../Speech/Recognizers/RecognizerBase.cs | 5 +- OscMultitool/Services/Speech/TextProcessor.cs | 14 +- OscMultitool/Ui/Pages/PageConfig.xaml.cs | 1 - OscMultitool/Ui/Pages/PageInput.xaml.cs | 1 - OscMultitool/Ui/Pages/PageOutput.xaml.cs | 3 +- OscMultitool/Ui/Pages/PageSpeech.xaml | 2 - OscMultitool/Ui/Pages/PageSpeech.xaml.cs | 2 +- .../Ui/Windows/ModifyApiPresetsWindow.xaml.cs | 11 +- .../Ui/Windows/ModifyCountersWindow.xaml.cs | 11 +- .../Ui/Windows/ModifyFiltersWindow.xaml | 2 +- .../Ui/Windows/ModifyFiltersWindow.xaml.cs | 11 +- .../ModifyOscRoutingFiltersWindow.xaml.cs | 11 +- .../Ui/Windows/ModifyReplacementsWindow.xaml | 11 +- .../Windows/ModifyReplacementsWindow.xaml.cs | 17 +- .../Ui/Windows/ModifyShortcutsWindow.xaml | 57 ++ .../Ui/Windows/ModifyShortcutsWindow.xaml.cs | 95 +++ OscMultitool/Utils.cs | 22 + 26 files changed, 893 insertions(+), 665 deletions(-) create mode 100644 OscMultitool/Models/ApiPresetModel.cs create mode 100644 OscMultitool/Models/ConfigModels.cs create mode 100644 OscMultitool/Models/CounterModel.cs create mode 100644 OscMultitool/Models/OscRoutingFilterModel.cs create mode 100644 OscMultitool/Models/RegexModels.cs create mode 100644 OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml create mode 100644 OscMultitool/Ui/Windows/ModifyShortcutsWindow.xaml.cs diff --git a/OscMultitool/Config.cs b/OscMultitool/Config.cs index 36c94fe..a6e16e7 100644 --- a/OscMultitool/Config.cs +++ b/OscMultitool/Config.cs @@ -1,10 +1,9 @@ -using Newtonsoft.Json; +using Hoscy.Models; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; -using System.Net.Http.Headers; using System.Text; -using System.Text.RegularExpressions; using System.Windows.Forms; namespace Hoscy @@ -88,23 +87,6 @@ private static void TryLoadFolderModels() #endregion #region Utility - /// - /// A combination of floor and ceil for comparables - /// - /// Type to compare - /// Value to compare - /// Minimum value - /// Maximum value - /// Value, if within bounds. Min, if value smaller than min. Max, if value larger than max. If max is smaller than min, min has priority - internal static T MinMax(T value, T min, T max) where T : IComparable - { - if (value.CompareTo(min) < 0) - return min; - if (value.CompareTo(max) > 0) - return max; - return value; - } - /// /// This exists as newtonsoft seems to have an issue with my way of creating a default config /// @@ -213,594 +195,6 @@ private static void UpdateConfig(ConfigModel config) config.ConfigVersion = 4; } - #endregion - - #region Models - /// - /// Model for storing all config data - /// - internal class ConfigModel - { - public int ConfigVersion { get; set; } = 0; - - public ConfigOscModel Osc { get; init; } = new(); - public ConfigSpeechModel Speech { get; init; } = new(); - public ConfigTextboxModel Textbox { get; init; } = new(); - public ConfigInputModel Input { get; init; } = new(); - public ConfigApiModel Api { get; init; } = new(); - public ConfigLoggerModel Debug { get; init; } = new(); - } - - /// - /// Model for storing all OSC related data (Ports, IPs, Addresses, Filters) - /// - internal class ConfigOscModel - { - //Routing Related - public string Ip { get; set; } = "127.0.0.1"; //Target IP for sending - public int Port //Target port for sending - { - get => _port; - set { _port = MinMax(value, -1, 65535); } - } - private int _port = 9000; - public int PortListen //Port HOSCY listens on - { - get => _portListen; - set { _portListen = MinMax(value, -1, 65535); } - } - private int _portListen = 9001; - public List RoutingFilters { get; set; } = new(); //Routing - - //Addresses for OSC Control - public string AddressManualMute { get; set; } = "/avatar/parameters/ToolMute"; - public string AddressManualSkipSpeech { get; set; } = "/avatar/parameters/ToolSkipSpeech"; - public string AddressManualSkipBox { get; set; } = "/avatar/parameters/ToolSkipBox"; - public string AddressEnableReplacements { get; set; } = "/avatar/parameters/ToolEnableReplacements"; - public string AddressEnableTextbox { get; set; } = "/avatar/parameters/ToolEnableBox"; - public string AddressEnableTts { get; set; } = "/avatar/parameters/ToolEnableTts"; - public string AddressEnableAutoMute { get; set; } = "/avatar/parameters/ToolEnableAutoMute"; - public string AddressListeningIndicator { get; set; } = "/avatar/parameters/MicListening"; - public string AddressGameMute { get; set; } = "/avatar/parameters/MuteSelf"; - public string AddressGameAfk { get; set; } = "/avatar/parameters/AFK"; - public string AddressGameTextbox { get; set; } = "/chatbox/input"; - public string AddressAddTextbox { get; set; } = "/hoscy/message"; - public string AddressAddTts { get; set; } = "/hoscy/tts"; - public string AddressAddNotification { get; set; } = "/hoscy/notification"; - public string AddressMediaPause { get; set; } = "/avatar/parameters/MediaPause"; - public string AddressMediaUnpause { get; set; } = "/avatar/parameters/MediaUnpause"; - public string AddressMediaRewind { get; set; } = "/avatar/parameters/MediaRewind"; - public string AddressMediaSkip { get; set; } = "/avatar/parameters/MediaSkip"; - public string AddressMediaInfo { get; set; } = "/avatar/parameters/MediaInfo"; - public string AddressMediaToggle { get; set; } = "/avatar/parameters/MediaToggle"; - - //Counter Related - public bool ShowCounterNotifications { get; set; } = false; //Display in Textbox - public float CounterDisplayDuration //Duration (in seconds) that counters will be accounted for in display - { - get => _counterDisplayDuration; - set { _counterDisplayDuration = MinMax(value, 0.01f, 30); } - } - private float _counterDisplayDuration = 10f; - - public float CounterDisplayCooldown //Duration (in seconds) that counters cannot be displayed - { - get => _counterDisplayCooldown; - set { _counterDisplayCooldown = MinMax(value, 0, 300); } - } - private float _counterDisplayCooldown = 0f; - - public List Counters { get; set; } = new(); - - //AFK Related - public bool ShowAfkDuration { get; set; } = false; //Display in Textbox - public float AfkDuration //Duration (in seconds) between initial AFK notifications - { - get => _afkDuration; - set { _afkDuration = MinMax(value, 5, 300); } - } - private float _afkDuration = 15; - - public float AfkDoubleDuration //Amount of times the duration gets displayed before duration doubles - { - get => _afkDoubleDuration; - set { _afkDoubleDuration = MinMax(value, 0, 60); } - } - private float _afkDoubleDuration = 12; - } - - /// - /// Model for storing all Speech related data (TTS, Models, Device Options) - /// - internal class ConfigSpeechModel - { - //Usage - public bool UseTextbox { get; set; } = true; //Result will be sent through textbox - public bool UseTts { get; set; } = false; //Result will be sent through TTS - public string MicId { get; set; } = string.Empty; //Recording microphone - public bool StartUnmuted { get; set; } = true; //Start recognition unmuted - public bool PlayMuteSound { get; set; } = false; //Play mute and unmute sounds - public bool MuteOnVrcMute { get; set; } = true; //Automatically mute when muted in VRC - public string ModelName { get; set; } = string.Empty; //Name of used model - - //TTS - public string TtsId { get; set; } = string.Empty; //Identifier for Microsoft TTS - public string SpeakerId { get; set; } = string.Empty; //Speaker for TTS out - public float SpeakerVolume //TTS volume - { - get => _speakerVolume; - set { _speakerVolume = MinMax(value, 0, 1); } - } - private float _speakerVolume = 0.5f; - public int MaxLenTtsString //Max length of strings that get TTS - { - get => _maxLenTtsString; - set { _maxLenTtsString = MinMax(value, 1, 99999); } - } - private int _maxLenTtsString = 500; - public bool SkipLongerMessages { get; set; } = true; //Skip longer messages instead of cutting off - - //Vosk - public Dictionary VoskModels { get; set; } = new(); //Model identifiers and filepaths - public string VoskModelCurrent { get; set; } = string.Empty; //Identifier for current model - public int VoskTimeout //Time (in milliseconds) allowed to pass where no new words are identified before manually cutting off - { - get => _voskTimeout; - set { _voskTimeout = MinMax(value, 500, 30000); } - } - private int _voskTimeout = 2500; - - //Windows - public string WinModelId { get; set; } = string.Empty; //Identifier for Microsoft Recognizer - - //Replacement - public List NoiseFilter { get; set; } = new(); //List of words deemed noise - public bool IgnoreCaps { get; set; } = true; //Ignoring caps when testing for replacements - public bool RemoveFullStop { get; set; } = true; //Removing the full stop at the end of a sentence if available - public bool UseReplacements { get; set; } = true; //Are replacements (and shortcuts) even used? - public List Shortcuts { get; set; } = new(); - public List Replacements { get; set; } = new(); - } - - /// - /// Model for storing all Textbox related data (Timeouts, MaxLength) - /// - internal class ConfigTextboxModel - { - //Timeout, Maxlen - public int MaxLength //Max length of string displayed before cutoff - { - get => _maxLength; - set { _maxLength = MinMax(value, 50, 130); } - } - private int _maxLength = 130; - public int TimeoutMultiplier //Add x milliseconds to timeout per 20 characters - { - get => _timeoutMultiplier; - set { _timeoutMultiplier = MinMax(value, 250, 10000); } - } - private int _timeoutMultiplier = 1250; - - public int MinimumTimeout //Minimum timeout (in milliseconds) that a message stays in the chatbox - { - get => _minimumTimeout; - set { _minimumTimeout = MinMax(value, 1250, 30000); } - } - private int _minimumTimeout = 3000; - - public int DefaultTimeout //Default timeout (in milliseconds) that a message stays in the chatbox - { - get => _defaultTimeout; - set { _defaultTimeout = MinMax(value, 1250, 30000); } - } - private int _defaultTimeout = 5000; - public bool DynamicTimeout { get; set; } = true; //Enables the dynamic timeout - - //Visual - public bool AutomaticClearNotification { get; set; } = true; //Automatic clearing after notification timeout - public bool AutomaticClearMessage { get; set; } = false; //Automatic clearing after message timeout - public bool UseIndicatorWithoutBox { get; set; } = false; //"Typing" indicator when box is disabled - - public string NotificationIndicatorLeft //Text to the left of a notification - { - get => _notificationIndicatorLeft; - set - { - _notificationIndicatorLeft = value.Length < 4 ? value : value[..3]; - _notificationIndicatorLength = CalcNotificationIndicatorLength(); - } - } - private string _notificationIndicatorLeft = "〈"; - - public string NotificationIndicatorRight //Text to the right of a notification - { - get => _notificationIndicatorRight; - set - { - _notificationIndicatorRight = value.Length < 4 ? value : value[..3]; - _notificationIndicatorLength = CalcNotificationIndicatorLength(); - } - } - private string _notificationIndicatorRight = "〉"; - private int _notificationIndicatorLength = 2; - - //Sound - public bool SoundOnMessage { get; set; } = true; //Play sound on textbox message - public bool SoundOnNotification { get; set; } = false; //Play sound on textbox notification - - //Notification handling - public bool UseNotificationPriority { get; set; } = true; //Only allows overwriting notification current not of lower priority - public bool UseNotificationSkip { get; set; } = true; //Skip notifications if a message is available - - //Media - public bool MediaShowStatus { get; set; } = false; //Display media information in textbox - public bool MediaAddAlbum { get; set; } = false; //Also add album to media information - - public string MediaPlayingVerb //xyz "songname" by "artist" on "album" - { - get => _mediaPlayingVerb; - set { _mediaPlayingVerb = value.Length > 0 ? value : "Playing"; } - } - private string _mediaPlayingVerb = "Playing"; - - public string MediaArtistVerb //Playing "songname" xyz "artist" on "album" - { - get => _mediaArtistVerb; - set { _mediaArtistVerb = value.Length > 0 ? value : "by"; } - } - private string _mediaArtistVerb = "by"; - - public string MediaAlbumVerb //Playing "songname" by "artist" xyz "album" - { - get => _mediaAlbumVerb; - set { _mediaAlbumVerb = value.Length > 0 ? value : "on"; } - } - private string _mediaAlbumVerb = "on"; - - public string MediaExtra { get; set; } = string.Empty; - - public List MediaFilters { get; set; } = new(); //Phrases filtered from media - - private int CalcNotificationIndicatorLength() - => _notificationIndicatorRight.Length + _notificationIndicatorLeft.Length; - - internal int NotificationIndicatorLength() => _notificationIndicatorLength; - } - - /// - /// Model for all API related data - /// - internal class ConfigApiModel - { - //General - public List Presets { get; set; } = new(); - - //Recognition - public string RecognitionPreset { get; set; } = string.Empty; //API preset for recognition - public int RecognitionMaxRecordingTime //Max time (in seconds) that can be recorded at once - { - get => _recognitionMaxRecordingTime; - set { _recognitionMaxRecordingTime = MinMax(value, 1, 300); } - } - private int _recognitionMaxRecordingTime = 30; - - //Translation - public string TranslationPreset { get; set; } = string.Empty; //API preset for translation - public bool TranslationSkipLongerMessages { get; set; } = true; //Skipping messages that are too long instead of partial translation - public int TranslationMaxTextLength //Maximum length of translatable text - { - get => _translationMaxTextLength; - set { _translationMaxTextLength = MinMax(value, 1, 60000); } - } - private int _translationMaxTextLength = 2000; - - //Azure - public string AzureRegion { get; set; } = string.Empty; //Region for azure - public string AzureKey { get; set; } = string.Empty; //Cognitive services key - public string AzureSpeechLanguage { get; set; } = string.Empty; //Language of TTS - public string AzureCustomEndpointSpeech { get; set; } = string.Empty; //Custom speech endpoint - public string AzureCustomEndpointRecognition { get; set; } = string.Empty; //Custom recognition endpoint - public string AzureVoiceCurrent { get; set; } = string.Empty; //Current azure voice - public List AzurePhrases { get; set; } = new(); //Phrases to set for improved recognition - public List AzureRecognitionLanguages { get; set; } = new(); //All voices for speech recognition - public Dictionary AzureVoices { get; set; } = new(); //All voices for TTS - - //Usage - public bool TranslateTts { get; set; } = false; //Automatically translate TTS - public bool TranslateTextbox { get; set; } = false; //Automatically translate textbox - public bool TranslationAllowExternal { get; set; } = false; //Translate external - public bool AddOriginalAfterTranslate { get; set; } = false; //Add original version after translation - public bool UseAzureTts { get; set; } = false; //Use azure TTS instead of Microsoft - - internal int GetIndex(string name) - { - for (int i = 0; i < Presets.Count; i++) - { - if (Presets[i].Name == name) - return i; - } - return -1; - } - - internal ApiPresetModel? GetPreset(string name) - { - var presetIndex = GetIndex(name); - - if (presetIndex == -1 || presetIndex >= Presets.Count) - return null; - - return Presets[presetIndex]; - } - } - - /// - /// Model for all Logging related data, this can currently only be changed in the file - /// - internal class ConfigLoggerModel - { - public bool OpenLogWindow { get; set; } = false; //Open log window on startup - public bool CheckUpdates { get; set; } = true; //Automatically check for updates on startup - public bool Error { get; set; } = true; - public bool Warning { get; set; } = true; - public bool Info { get; set; } = true; - public bool PrioInfo { get; set; } = true; - public bool Log { get; set; } = true; - public bool Debug { get; set; } = false; - public List LogFilters { get; set; } = new(); //Phrases filtered from logs - } - - /// - /// Model for all Input related data (Presets, Sending Options) - /// - internal class ConfigInputModel - { - public bool UseTts { get; set; } = false; //Convert input to TTS - public bool UseTextbox { get; set; } = true; //Convert input to textbox - public bool TriggerCommands { get; set; } = true; //Input triggers commands - public bool TriggerReplace { get; set; } = true; //Input triggers replacements - public bool IgnoreCaps { get;set; } = true; //Ignore caps for commands and replacements - public bool AllowTranslation { get; set; } = true; //Translate input - public Dictionary Presets { get; set; } = new(); //Presets for quick access - } - #endregion - - #region Extra Models - /// - /// Model for storing Routing Filter data - /// - internal class OscRoutingFilterModel - { - public string Name - { - get => _name; - set { _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value; } - } - private string _name = "Unnamed Filter"; - public int Port - { - get => _port; - set { _port = MinMax(value, -1, 65535); } - } - private int _port = -1; - public string Ip { get; set; } = "127.0.0.1"; - public List Filters { get; set; } = new(); - - private bool _isValid = true; - public override string ToString() - => $"{(_isValid ? "" : "[x]")}{Name} => {Ip}:{Port}"; - - /// - /// Sets validity to be displayed in filter window - /// - internal void SetValidity(bool state) - => _isValid = state; - } - - internal class ReplacementModel - { - public string Text - { - get => _text; - set { - _text = string.IsNullOrWhiteSpace(value) ? "New Value" : value; - _regexPattern = $@"(?<= |\b){Regex.Escape(_text)}(?=$| |\b)"; - _lowercaseText = _text.ToLower(); - } - } - private string _text = "New Value"; - private string _regexPattern = $@"(?<= |\b)New\ Value(?= |\b)"; //Pattern for replacing text when used as replacement - private string _lowercaseText = "new value"; //Lowercase version when checking for shortcuts - - public string Replacement { get; set; } = "Example"; - public bool Enabled { get; set; } = true; - - public ReplacementModel(string text, string replacement, bool enabled = true) - { - Text = text; - Replacement = replacement; - Enabled = enabled; - } - public ReplacementModel() { } - - internal string RegexPattern() => _regexPattern; - internal string LowercaseText() => _lowercaseText; - - public override string ToString() - => $"{(Enabled ? "" : "[x] ")}{Text} => {Replacement}"; - } - - internal class ApiPresetModel - { - public string Name - { - get => _name; - set { _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Preset" : value; } - } - private string _name = "Unnamed Preset"; - public string SentData { get; set; } = @"{""data"" : ""[T]""}"; - public Dictionary HeaderValues { get; set; } = new(); - public string ContentType { get; set; } = "application/json"; - public string ResultField { get; set; } = "result"; - - public string TargetUrl - { - get => _targetUrl; - set - { - _targetUrl = value; - _fullTargetUrl = value.StartsWith("h") ? value : "https://" + value; - } - } - private string _targetUrl = string.Empty; - private string _fullTargetUrl = string.Empty; - - public string Authorization - { - get => _authorization; - set - { - _authorization = string.Empty; - _authenticationHeader = null; - - if (string.IsNullOrWhiteSpace(value)) - return; - - try { - _authorization = value; - var authSplit = value.Split(' '); - - if (authSplit.Length == 1) - _authenticationHeader = new(authSplit[0]); - else if (authSplit.Length > 1) - _authenticationHeader = new(authSplit[0], string.Join(' ', authSplit[1..])); - } - catch { } - } - } - private string _authorization = string.Empty; - private AuthenticationHeaderValue? _authenticationHeader = null; - - public int ConnectionTimeout - { - get => _connectionTimeout; - set { _connectionTimeout = MinMax(value, 25, 60000); } - } - private int _connectionTimeout = 3000; - - internal string FullTargetUrl() => _fullTargetUrl; - internal AuthenticationHeaderValue? AuthenticationHeader() => _authenticationHeader; - - internal bool IsValid() - => !string.IsNullOrWhiteSpace(TargetUrl) - && !string.IsNullOrWhiteSpace(SentData) - && !string.IsNullOrWhiteSpace(ResultField) - && !string.IsNullOrWhiteSpace(ContentType); - } - - internal class CounterModel - { - public string Name - { - get => _name; - set { _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Counter" : value; } - } - private string _name = "Unnamed Counter"; - public uint Count { get; set; } = 0; - public DateTime LastUsed { get; set; } = DateTime.MinValue; - public bool Enabled { get; set; } = true; - public float Cooldown - { - get => _cooldown; - set { _cooldown = MinMax(value, 0, 3600); } - } - private float _cooldown = 0; - - public string Parameter - { - get => _parameter; - set - { - _parameter = value; - _fullParameter = value.StartsWith("/") ? value : "/avatar/parameters/" + value; - } - } - private string _parameter = "Parameter"; - private string _fullParameter = "/avatar/parameters/Parameter"; - - internal void Increase() - { - Count++; - LastUsed = DateTime.Now; - } - - internal string FullParameter() => _fullParameter; - - public override string ToString() - => $"{(Enabled ? "" : "[x] ")}{Name}: {Count:N0}"; - } - - internal class FilterModel - { - public string Name - { - get => _name; - set { _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value; } - } - private string _name = "Unnamed Filter"; - public string FilterString - { - get => _filterString; - set - { - _filterString = string.IsNullOrWhiteSpace(value) ? "Filter Text" : value; - UpdateRegex(); - } - } - private string _filterString = "Filter Text"; - public bool Enabled { get; set; } = true; - public bool IgnoreCase - { - get => _ignoreCase; - set - { - _ignoreCase = value; - UpdateRegex(); - } - } - private bool _ignoreCase = false; - public bool UseRegex - { - get => _useRegex; - set - { - _useRegex = value; - UpdateRegex(); - } - } - private bool _useRegex = false; - private Regex? _filterRegex; - - public FilterModel(string name, string filterString) - { - Name = name; - FilterString = filterString; - } - public FilterModel() { } - - private void UpdateRegex() - => _filterRegex = _useRegex ? new(_filterString, _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant) : null; - - internal bool Matches(string compare) - { - if (_filterRegex == null) - return compare.Contains(_filterString, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); - - return _filterRegex.IsMatch(compare); - } - - public override string ToString() - => $"{(Enabled ? "" : "[x] ")}{_name} ={(_useRegex ? "R" : string.Empty)}{(_ignoreCase ? "C" : string.Empty)}> {_filterString}"; - } - #endregion + #endregion } } diff --git a/OscMultitool/Hoscy.csproj b/OscMultitool/Hoscy.csproj index 410efc7..abeb04f 100644 --- a/OscMultitool/Hoscy.csproj +++ b/OscMultitool/Hoscy.csproj @@ -7,8 +7,8 @@ true Resources\hoscy_circle.ico AnyCPU;x64 - 0.6.8 - 0.6.8 + 0.7 + 0.7 https://github.com/PaciStardust/HOSCY https://github.com/PaciStardust/HOSCY README.md @@ -78,6 +78,9 @@ Code + + Code + Code @@ -117,6 +120,9 @@ $(DefaultXamlRuntime) Designer + + $(DefaultXamlRuntime) + $(DefaultXamlRuntime) Designer diff --git a/OscMultitool/Models/ApiPresetModel.cs b/OscMultitool/Models/ApiPresetModel.cs new file mode 100644 index 0000000..0710571 --- /dev/null +++ b/OscMultitool/Models/ApiPresetModel.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Net.Http.Headers; + +namespace Hoscy.Models +{ + internal class ApiPresetModel + { + public string Name + { + get => _name; + set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Preset" : value; + } + private string _name = "Unnamed Preset"; + + public string SentData { get; set; } = @"{""data"" : ""[T]""}"; + public Dictionary HeaderValues { get; set; } = new(); + public string ContentType { get; set; } = "application/json"; + public string ResultField { get; set; } = "result"; + + public string TargetUrl + { + get => _targetUrl; + set + { + _targetUrl = value; + _fullTargetUrl = value.StartsWith("h") ? value : "https://" + value; + } + } + private string _targetUrl = string.Empty; + private string _fullTargetUrl = string.Empty; + + public string Authorization + { + get => _authorization; + set + { + _authorization = string.Empty; + _authenticationHeader = null; + + if (string.IsNullOrWhiteSpace(value)) + return; + + try + { + _authorization = value; + var authSplit = value.Split(' '); + + if (authSplit.Length == 1) + _authenticationHeader = new(authSplit[0]); + else if (authSplit.Length > 1) + _authenticationHeader = new(authSplit[0], string.Join(' ', authSplit[1..])); + } + catch { } + } + } + private string _authorization = string.Empty; + private AuthenticationHeaderValue? _authenticationHeader = null; + + public int ConnectionTimeout + { + get => _connectionTimeout; + set => _connectionTimeout = Utils.MinMax(value, 25, 60000); + } + private int _connectionTimeout = 3000; + + internal string FullTargetUrl() => _fullTargetUrl; + internal AuthenticationHeaderValue? AuthenticationHeader() => _authenticationHeader; + + internal bool IsValid() + => !string.IsNullOrWhiteSpace(TargetUrl) + && !string.IsNullOrWhiteSpace(SentData) + && !string.IsNullOrWhiteSpace(ResultField) + && !string.IsNullOrWhiteSpace(ContentType); + } +} diff --git a/OscMultitool/Models/ConfigModels.cs b/OscMultitool/Models/ConfigModels.cs new file mode 100644 index 0000000..4cc8079 --- /dev/null +++ b/OscMultitool/Models/ConfigModels.cs @@ -0,0 +1,349 @@ +using System.Collections.Generic; + +namespace Hoscy.Models +{ + /// + /// Model for storing all config data + /// + internal class ConfigModel + { + public int ConfigVersion { get; set; } = 0; + + public ConfigOscModel Osc { get; init; } = new(); + public ConfigSpeechModel Speech { get; init; } = new(); + public ConfigTextboxModel Textbox { get; init; } = new(); + public ConfigInputModel Input { get; init; } = new(); + public ConfigApiModel Api { get; init; } = new(); + public ConfigLoggerModel Debug { get; init; } = new(); + } + + /// + /// Model for all API related data + /// + internal class ConfigApiModel + { + //General + public List Presets { get; set; } = new(); + + //Recognition + public string RecognitionPreset { get; set; } = string.Empty; //API preset for recognition + public int RecognitionMaxRecordingTime //Max time (in seconds) that can be recorded at once + { + get => _recognitionMaxRecordingTime; + set => _recognitionMaxRecordingTime = Utils.MinMax(value, 1, 300); + } + private int _recognitionMaxRecordingTime = 30; + + //Translation + public string TranslationPreset { get; set; } = string.Empty; //API preset for translation + public bool TranslationSkipLongerMessages { get; set; } = true; //Skipping messages that are too long instead of partial translation + public int TranslationMaxTextLength //Maximum length of translatable text + { + get => _translationMaxTextLength; + set => _translationMaxTextLength = Utils.MinMax(value, 1, 60000); + } + private int _translationMaxTextLength = 2000; + + //Azure + public string AzureRegion { get; set; } = string.Empty; //Region for azure + public string AzureKey { get; set; } = string.Empty; //Cognitive services key + public string AzureSpeechLanguage { get; set; } = string.Empty; //Language of TTS + public string AzureCustomEndpointSpeech { get; set; } = string.Empty; //Custom speech endpoint + public string AzureCustomEndpointRecognition { get; set; } = string.Empty; //Custom recognition endpoint + public string AzureVoiceCurrent { get; set; } = string.Empty; //Current azure voice + public List AzurePhrases { get; set; } = new(); //Phrases to set for improved recognition + public List AzureRecognitionLanguages { get; set; } = new(); //All voices for speech recognition + public Dictionary AzureVoices { get; set; } = new(); //All voices for TTS + + //Usage + public bool TranslateTts { get; set; } = false; //Automatically translate TTS + public bool TranslateTextbox { get; set; } = false; //Automatically translate textbox + public bool TranslationAllowExternal { get; set; } = false; //Translate external + public bool AddOriginalAfterTranslate { get; set; } = false; //Add original version after translation + public bool UseAzureTts { get; set; } = false; //Use azure TTS instead of Microsoft + + internal int GetIndex(string name) + { + for (int i = 0; i < Presets.Count; i++) + { + if (Presets[i].Name == name) + return i; + } + return -1; + } + + internal ApiPresetModel? GetPreset(string name) + { + var presetIndex = GetIndex(name); + + if (presetIndex == -1 || presetIndex >= Presets.Count) + return null; + + return Presets[presetIndex]; + } + } + + /// + /// Model for all Input related data (Presets, Sending Options) + /// + internal class ConfigInputModel + { + public bool UseTts { get; set; } = false; //Convert input to TTS + public bool UseTextbox { get; set; } = true; //Convert input to textbox + public bool TriggerCommands { get; set; } = true; //Input triggers commands + public bool TriggerReplace { get; set; } = true; //Input triggers replacements + public bool AllowTranslation { get; set; } = true; //Translate input + public Dictionary Presets { get; set; } = new(); //Presets for quick access + } + + /// + /// Model for all Logging related data, this can currently only be changed in the file + /// + internal class ConfigLoggerModel + { + public bool OpenLogWindow { get; set; } = false; //Open log window on startup + public bool CheckUpdates { get; set; } = true; //Automatically check for updates on startup + public bool Error { get; set; } = true; + public bool Warning { get; set; } = true; + public bool Info { get; set; } = true; + public bool PrioInfo { get; set; } = true; + public bool Log { get; set; } = true; + public bool Debug { get; set; } = false; + public List LogFilters { get; set; } = new(); //Phrases filtered from logs + } + + /// + /// Model for storing all OSC related data (Ports, IPs, Addresses, Filters) + /// + internal class ConfigOscModel + { + //Routing Related + public string Ip { get; set; } = "127.0.0.1"; //Target IP for sending + public int Port //Target port for sending + { + get => _port; + set => _port = Utils.MinMax(value, -1, 65535); + } + private int _port = 9000; + public int PortListen //Port HOSCY listens on + { + get => _portListen; + set => _portListen = Utils.MinMax(value, -1, 65535); + } + private int _portListen = 9001; + public List RoutingFilters { get; set; } = new(); //Routing + + //Addresses for OSC Control + public string AddressManualMute { get; set; } = "/avatar/parameters/ToolMute"; + public string AddressManualSkipSpeech { get; set; } = "/avatar/parameters/ToolSkipSpeech"; + public string AddressManualSkipBox { get; set; } = "/avatar/parameters/ToolSkipBox"; + public string AddressEnableReplacements { get; set; } = "/avatar/parameters/ToolEnableReplacements"; + public string AddressEnableTextbox { get; set; } = "/avatar/parameters/ToolEnableBox"; + public string AddressEnableTts { get; set; } = "/avatar/parameters/ToolEnableTts"; + public string AddressEnableAutoMute { get; set; } = "/avatar/parameters/ToolEnableAutoMute"; + public string AddressListeningIndicator { get; set; } = "/avatar/parameters/MicListening"; + public string AddressGameMute { get; set; } = "/avatar/parameters/MuteSelf"; + public string AddressGameAfk { get; set; } = "/avatar/parameters/AFK"; + public string AddressGameTextbox { get; set; } = "/chatbox/input"; + public string AddressAddTextbox { get; set; } = "/hoscy/message"; + public string AddressAddTts { get; set; } = "/hoscy/tts"; + public string AddressAddNotification { get; set; } = "/hoscy/notification"; + public string AddressMediaPause { get; set; } = "/avatar/parameters/MediaPause"; + public string AddressMediaUnpause { get; set; } = "/avatar/parameters/MediaUnpause"; + public string AddressMediaRewind { get; set; } = "/avatar/parameters/MediaRewind"; + public string AddressMediaSkip { get; set; } = "/avatar/parameters/MediaSkip"; + public string AddressMediaInfo { get; set; } = "/avatar/parameters/MediaInfo"; + public string AddressMediaToggle { get; set; } = "/avatar/parameters/MediaToggle"; + + //Counter Related + public bool ShowCounterNotifications { get; set; } = false; //Display in Textbox + public float CounterDisplayDuration //Duration (in seconds) that counters will be accounted for in display + { + get => _counterDisplayDuration; + set => _counterDisplayDuration = Utils.MinMax(value, 0.01f, 30); + } + private float _counterDisplayDuration = 10f; + + public float CounterDisplayCooldown //Duration (in seconds) that counters cannot be displayed + { + get => _counterDisplayCooldown; + set => _counterDisplayCooldown = Utils.MinMax(value, 0, 300); + } + private float _counterDisplayCooldown = 0f; + + public List Counters { get; set; } = new(); + + //AFK Related + public bool ShowAfkDuration { get; set; } = false; //Display in Textbox + public float AfkDuration //Duration (in seconds) between initial AFK notifications + { + get => _afkDuration; + set => _afkDuration = Utils.MinMax(value, 5, 300); + } + private float _afkDuration = 15; + + public float AfkDoubleDuration //Amount of times the duration gets displayed before duration doubles + { + get => _afkDoubleDuration; + set => _afkDoubleDuration = Utils.MinMax(value, 0, 60); + } + private float _afkDoubleDuration = 12; + } + + /// + /// Model for storing all Speech related data (TTS, Models, Device Options) + /// + internal class ConfigSpeechModel + { + //Usage + public bool UseTextbox { get; set; } = true; //Result will be sent through textbox + public bool UseTts { get; set; } = false; //Result will be sent through TTS + public string MicId { get; set; } = string.Empty; //Recording microphone + public bool StartUnmuted { get; set; } = true; //Start recognition unmuted + public bool PlayMuteSound { get; set; } = false; //Play mute and unmute sounds + public bool MuteOnVrcMute { get; set; } = true; //Automatically mute when muted in VRC + public string ModelName { get; set; } = string.Empty; //Name of used model + + //TTS + public string TtsId { get; set; } = string.Empty; //Identifier for Microsoft TTS + public string SpeakerId { get; set; } = string.Empty; //Speaker for TTS out + public float SpeakerVolume //TTS volume + { + get => _speakerVolume; + set => _speakerVolume = Utils.MinMax(value, 0, 1); + } + private float _speakerVolume = 0.5f; + public int MaxLenTtsString //Max length of strings that get TTS + { + get => _maxLenTtsString; + set => _maxLenTtsString = Utils.MinMax(value, 1, 99999); + } + private int _maxLenTtsString = 500; + public bool SkipLongerMessages { get; set; } = true; //Skip longer messages instead of cutting off + + //Vosk + public Dictionary VoskModels { get; set; } = new(); //Model identifiers and filepaths + public string VoskModelCurrent { get; set; } = string.Empty; //Identifier for current model + public int VoskTimeout //Time (in milliseconds) allowed to pass where no new words are identified before manually cutting off + { + get => _voskTimeout; + set => _voskTimeout = Utils.MinMax(value, 500, 30000); + } + private int _voskTimeout = 2500; + + //Windows + public string WinModelId { get; set; } = string.Empty; //Identifier for Microsoft Recognizer + + //Replacement + public List NoiseFilter { get; set; } = new(); //List of words deemed noise + public bool RemoveFullStop { get; set; } = true; //todo: make default option + public bool UseReplacements { get; set; } = true; //Are replacements (and shortcuts) even used? + public List Shortcuts { get; set; } = new(); + public List Replacements { get; set; } = new(); + } + + /// + /// Model for storing all Textbox related data (Timeouts, MaxLength) + /// + internal class ConfigTextboxModel + { + //Timeout, Maxlen + public int MaxLength //Max length of string displayed before cutoff + { + get => _maxLength; + set => _maxLength = Utils.MinMax(value, 50, 130); + } + private int _maxLength = 130; + public int TimeoutMultiplier //Add x milliseconds to timeout per 20 characters + { + get => _timeoutMultiplier; + set => _timeoutMultiplier = Utils.MinMax(value, 250, 10000); + } + private int _timeoutMultiplier = 1250; + + public int MinimumTimeout //Minimum timeout (in milliseconds) that a message stays in the chatbox + { + get => _minimumTimeout; + set => _minimumTimeout = Utils.MinMax(value, 1250, 30000); + } + private int _minimumTimeout = 3000; + + public int DefaultTimeout //Default timeout (in milliseconds) that a message stays in the chatbox + { + get => _defaultTimeout; + set => _defaultTimeout = Utils.MinMax(value, 1250, 30000); + } + private int _defaultTimeout = 5000; + public bool DynamicTimeout { get; set; } = true; //Enables the dynamic timeout + + //Visual + public bool AutomaticClearNotification { get; set; } = true; //Automatic clearing after notification timeout + public bool AutomaticClearMessage { get; set; } = false; //Automatic clearing after message timeout + public bool UseIndicatorWithoutBox { get; set; } = false; //"Typing" indicator when box is disabled + + public string NotificationIndicatorLeft //Text to the left of a notification + { + get => _notificationIndicatorLeft; + set + { + _notificationIndicatorLeft = value.Length < 4 ? value : value[..3]; + _notificationIndicatorLength = CalcNotificationIndicatorLength(); + } + } + private string _notificationIndicatorLeft = "〈"; + + public string NotificationIndicatorRight //Text to the right of a notification + { + get => _notificationIndicatorRight; + set + { + _notificationIndicatorRight = value.Length < 4 ? value : value[..3]; + _notificationIndicatorLength = CalcNotificationIndicatorLength(); + } + } + private string _notificationIndicatorRight = "〉"; + private int _notificationIndicatorLength = 2; + + //Sound + public bool SoundOnMessage { get; set; } = true; //Play sound on textbox message + public bool SoundOnNotification { get; set; } = false; //Play sound on textbox notification + + //Notification handling + public bool UseNotificationPriority { get; set; } = true; //Only allows overwriting notification current not of lower priority + public bool UseNotificationSkip { get; set; } = true; //Skip notifications if a message is available + + //Media + public bool MediaShowStatus { get; set; } = false; //Display media information in textbox + public bool MediaAddAlbum { get; set; } = false; //Also add album to media information + + public string MediaPlayingVerb //xyz "songname" by "artist" on "album" + { + get => _mediaPlayingVerb; + set => _mediaPlayingVerb = value.Length > 0 ? value : "Playing"; + } + private string _mediaPlayingVerb = "Playing"; + + public string MediaArtistVerb //Playing "songname" xyz "artist" on "album" + { + get => _mediaArtistVerb; + set => _mediaArtistVerb = value.Length > 0 ? value : "by"; + } + private string _mediaArtistVerb = "by"; + + public string MediaAlbumVerb //Playing "songname" by "artist" xyz "album" + { + get => _mediaAlbumVerb; + set => _mediaAlbumVerb = value.Length > 0 ? value : "on"; + } + private string _mediaAlbumVerb = "on"; + + public string MediaExtra { get; set; } = string.Empty; + + public List MediaFilters { get; set; } = new(); //Phrases filtered from media + + private int CalcNotificationIndicatorLength() + => _notificationIndicatorRight.Length + _notificationIndicatorLeft.Length; + + internal int NotificationIndicatorLength() => _notificationIndicatorLength; + } +} diff --git a/OscMultitool/Models/CounterModel.cs b/OscMultitool/Models/CounterModel.cs new file mode 100644 index 0000000..cc0d61b --- /dev/null +++ b/OscMultitool/Models/CounterModel.cs @@ -0,0 +1,46 @@ +using System; + +namespace Hoscy.Models +{ + internal class CounterModel + { + public string Name + { + get => _name; + set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Counter" : value; + } + private string _name = "Unnamed Counter"; + public uint Count { get; set; } = 0; + public DateTime LastUsed { get; set; } = DateTime.MinValue; + public bool Enabled { get; set; } = true; + public float Cooldown + { + get => _cooldown; + set => _cooldown = Utils.MinMax(value, 0, 3600); + } + private float _cooldown = 0; + + public string Parameter + { + get => _parameter; + set + { + _parameter = value; + _fullParameter = value.StartsWith("/") ? value : "/avatar/parameters/" + value; + } + } + private string _parameter = "Parameter"; + private string _fullParameter = "/avatar/parameters/Parameter"; + + internal void Increase() + { + Count++; + LastUsed = DateTime.Now; + } + + internal string FullParameter() => _fullParameter; + + public override string ToString() + => $"{(Enabled ? "" : "[x] ")}{Name}: {Count:N0}"; + } +} diff --git a/OscMultitool/Models/OscRoutingFilterModel.cs b/OscMultitool/Models/OscRoutingFilterModel.cs new file mode 100644 index 0000000..7e70f0a --- /dev/null +++ b/OscMultitool/Models/OscRoutingFilterModel.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace Hoscy.Models +{ + internal class OscRoutingFilterModel + { + public string Name + { + get => _name; + set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value; + } + private string _name = "Unnamed Filter"; + public int Port + { + get => _port; + set => _port = Utils.MinMax(value, -1, 65535); + } + private int _port = -1; + public string Ip { get; set; } = "127.0.0.1"; + public List Filters { get; set; } = new(); + + private bool _isValid = true; + public override string ToString() + => $"{(_isValid ? "" : "[x]")}{Name} => {Ip}:{Port}"; + + /// + /// Sets validity to be displayed in filter window + /// + internal void SetValidity(bool state) + => _isValid = state; + } +} diff --git a/OscMultitool/Models/RegexModels.cs b/OscMultitool/Models/RegexModels.cs new file mode 100644 index 0000000..842318f --- /dev/null +++ b/OscMultitool/Models/RegexModels.cs @@ -0,0 +1,150 @@ +using System; +using System.Text.RegularExpressions; + +namespace Hoscy.Models +{ + internal abstract class RegexFilteredModelBase + { + public bool Enabled { get; set; } = true; + public bool IgnoreCase + { + get => _ignoreCase; + set + { + _ignoreCase = value; + UpdateRegex(); + } + } + protected bool _ignoreCase = true; + public bool UseRegex + { + get => _useRegex; + set + { + _useRegex = value; + UpdateRegex(); + } + } + protected bool _useRegex = false; + + protected Regex? _regex; + + protected abstract void UpdateRegex(); + } + + internal class FilterModel : RegexFilteredModelBase + { + public string Name + { + get => _name; + set => _name = string.IsNullOrWhiteSpace(value) ? "Unnamed Filter" : value; + } + private string _name = "Unnamed Filter"; + public string FilterString + { + get => _filterString; + set + { + _filterString = string.IsNullOrWhiteSpace(value) ? "Filter Text" : value; + UpdateRegex(); + } + } + private string _filterString = "Filter Text"; + + public FilterModel(string name, string filterString) + { + Name = name; + FilterString = filterString; + } + public FilterModel() { } + + protected override void UpdateRegex() + => _regex = _useRegex ? new(_filterString, _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant) : null; + + internal bool Matches(string compare) + { + if (_regex == null) + return compare.Contains(_filterString, _ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + + return _regex.IsMatch(compare); + } + + public override string ToString() + => $"{(Enabled ? "" : "[x] ")}{_name} ={(_useRegex ? "[R]" : string.Empty)}{(_ignoreCase ? string.Empty : "[C]")}> {_filterString}"; + } + + internal abstract class RegexTextChangingModelBase : RegexFilteredModelBase + { + public string Text + { + get => _text; + set + { + _text = string.IsNullOrWhiteSpace(value) ? "New Text" : value; + UpdateRegex(); + } + } + protected string _text = "New Text"; + + public string Replacement { get; set; } = "Example"; + + public RegexTextChangingModelBase(string text, string replacement) : base() + { + Text = text; + Replacement = replacement; + } + public RegexTextChangingModelBase() + { + _ignoreCase = true; + } + + public override string ToString() + => $"{(Enabled ? "" : "[x] ")}{Text} ={(_useRegex ? "[R]" : string.Empty)}{(_ignoreCase ? string.Empty : "[C]")}> {Replacement}"; + } + + internal class ReplacementModel : RegexTextChangingModelBase //todo: test + { + protected override void UpdateRegex() + { + RegexOptions rexOpt = _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant; + _regex = _useRegex ? new(_text, rexOpt) : new($@"(?<= |\b){Regex.Escape(_text)}(?=$| |\b)", rexOpt); + } + + public ReplacementModel(string text, string replacement) + { + Text = text; + Replacement = replacement; + } + public ReplacementModel() { } + + internal string Replace(string text) + => _regex?.Replace(text, Replacement) ?? text; + } + + internal class ShortcutModel : RegexTextChangingModelBase //todo: test, unify to one editor window + { + protected override void UpdateRegex() + { + if (UseRegex && _text.StartsWith('^') && _text.EndsWith('$')) + _text = _text.TrimStart('^').TrimEnd('$'); + + RegexOptions rexOpt = _ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None | RegexOptions.CultureInvariant; + _regex = UseRegex ? new($"^{_text}$", rexOpt) : null; + } + + public ShortcutModel(string text, string replacement) + { + Text = text; + Replacement = replacement; + } + public ShortcutModel() { } + + internal bool Compare(string text) + { + if (_regex == null) + return Text.Equals(text, IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + + return _regex.IsMatch(text); + } + } +} diff --git a/OscMultitool/Services/Api/ApiClient.cs b/OscMultitool/Services/Api/ApiClient.cs index de482fb..c78065f 100644 --- a/OscMultitool/Services/Api/ApiClient.cs +++ b/OscMultitool/Services/Api/ApiClient.cs @@ -1,4 +1,5 @@ -using System.Net.Http; +using Hoscy.Models; +using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -6,9 +7,9 @@ namespace Hoscy.Services.Api { internal class ApiClient { - private Config.ApiPresetModel? _preset; + private ApiPresetModel? _preset; - internal bool LoadPreset(Config.ApiPresetModel preset) + internal bool LoadPreset(ApiPresetModel preset) { if (preset.Equals(_preset)) return true; diff --git a/OscMultitool/Services/OscControl/OscDataHandler.cs b/OscMultitool/Services/OscControl/OscDataHandler.cs index b58e8ac..1c4ab46 100644 --- a/OscMultitool/Services/OscControl/OscDataHandler.cs +++ b/OscMultitool/Services/OscControl/OscDataHandler.cs @@ -103,7 +103,6 @@ private static void HandleToolDataString(string address, string value) { var tProcessor = new TextProcessor() { - ReplaceCaseInsensitive = true, TriggerReplace = true, TriggerCommands = true, UseTextbox = useTextbox, diff --git a/OscMultitool/Services/Speech/Recognizers/RecognizerBase.cs b/OscMultitool/Services/Speech/Recognizers/RecognizerBase.cs index 8bfd7e2..71c3207 100644 --- a/OscMultitool/Services/Speech/Recognizers/RecognizerBase.cs +++ b/OscMultitool/Services/Speech/Recognizers/RecognizerBase.cs @@ -115,7 +115,6 @@ internal static void ProcessMessage(string message) var processor = new TextProcessor() { TriggerReplace = Config.Speech.UseReplacements, - ReplaceCaseInsensitive = Config.Speech.IgnoreCaps, TriggerCommands = true, @@ -152,13 +151,11 @@ protected static string Denoise(string message) /// internal static void UpdateDenoiseRegex() { - RegexOptions opt = Config.Speech.IgnoreCaps ? RegexOptions.IgnoreCase : RegexOptions.None; - var filterWords = Config.Speech.NoiseFilter.Select(x => $"(?:{x})"); var filterCombined = string.Join('|', filterWords); var regString = $"^(?:\\b(?:{filterCombined})\\b)?(.*?)(?:\\b(?:{filterCombined})\\b)?$"; Logger.PInfo($"Updated denoiser ({regString})"); - _denoiseFilter = new Regex(regString, opt | RegexOptions.CultureInvariant); + _denoiseFilter = new Regex(regString, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); } #endregion } diff --git a/OscMultitool/Services/Speech/TextProcessor.cs b/OscMultitool/Services/Speech/TextProcessor.cs index cc6ba29..4860858 100644 --- a/OscMultitool/Services/Speech/TextProcessor.cs +++ b/OscMultitool/Services/Speech/TextProcessor.cs @@ -2,7 +2,6 @@ using Hoscy.Services.Api; using Hoscy.Ui.Pages; using System; -using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -15,7 +14,6 @@ internal class TextProcessor internal bool UseTts { get; init; } = false; internal bool TriggerCommands { get; init; } = false; internal bool TriggerReplace { get; init; } = false; - internal bool ReplaceCaseInsensitive { get; init; } = false; internal bool AllowTranslate { get; init; } = false; #region Processing @@ -74,26 +72,22 @@ private async Task ProcessInternal(string message) PageInfo.SetMessage(message, UseTextbox, UseTts); } - private static readonly List _shortcuts = Config.Speech.Shortcuts; - private static readonly List _replacements = Config.Speech.Replacements; /// /// Replaces message or parts of it /// private string ReplaceMessage(string message) { //Splitting and checking for replacements - var regexOpt = RegexOptions.CultureInvariant | (ReplaceCaseInsensitive ? RegexOptions.IgnoreCase : RegexOptions.None); - foreach (var r in _replacements) + foreach (var r in Config.Speech.Replacements) { if (r.Enabled) - message = Regex.Replace(message, r.RegexPattern(), r.Replacement, regexOpt); + message = r.Replace(message); } //Checking for shortcuts - var compareText = ReplaceCaseInsensitive ? message.ToLower() : message; - foreach (var s in _shortcuts) + foreach (var s in Config.Speech.Shortcuts) { - if (s.Enabled && compareText == (ReplaceCaseInsensitive ? s.LowercaseText() : s.Text)) + if (s.Enabled && s.Compare(message)) { message = s.Replacement; break; diff --git a/OscMultitool/Ui/Pages/PageConfig.xaml.cs b/OscMultitool/Ui/Pages/PageConfig.xaml.cs index 72873cf..a04eead 100644 --- a/OscMultitool/Ui/Pages/PageConfig.xaml.cs +++ b/OscMultitool/Ui/Pages/PageConfig.xaml.cs @@ -4,7 +4,6 @@ using Hoscy.Ui.Windows; using System.Windows; using System.Windows.Controls; -using System.Windows.Media.Animation; namespace Hoscy.Ui.Pages { diff --git a/OscMultitool/Ui/Pages/PageInput.xaml.cs b/OscMultitool/Ui/Pages/PageInput.xaml.cs index f32da28..8296e68 100644 --- a/OscMultitool/Ui/Pages/PageInput.xaml.cs +++ b/OscMultitool/Ui/Pages/PageInput.xaml.cs @@ -48,7 +48,6 @@ private void SendMessage() var tProcessor = new TextProcessor() { - ReplaceCaseInsensitive = Config.Input.IgnoreCaps, TriggerCommands = Config.Input.TriggerCommands, TriggerReplace = Config.Input.TriggerReplace, UseTextbox = Config.Input.UseTextbox, diff --git a/OscMultitool/Ui/Pages/PageOutput.xaml.cs b/OscMultitool/Ui/Pages/PageOutput.xaml.cs index bcbca09..017bfc1 100644 --- a/OscMultitool/Ui/Pages/PageOutput.xaml.cs +++ b/OscMultitool/Ui/Pages/PageOutput.xaml.cs @@ -1,5 +1,4 @@ -using Hoscy.Services.OscControl; -using Hoscy.Services.Speech; +using Hoscy.Services.Speech; using Hoscy.Services.Speech.Utilities; using Hoscy.Ui.Windows; using System; diff --git a/OscMultitool/Ui/Pages/PageSpeech.xaml b/OscMultitool/Ui/Pages/PageSpeech.xaml index da8abdd..0d5a852 100644 --- a/OscMultitool/Ui/Pages/PageSpeech.xaml +++ b/OscMultitool/Ui/Pages/PageSpeech.xaml @@ -44,7 +44,6 @@