Skip to content

Commit

Permalink
Added authorization and examples to API Presets, Config saving on Rec…
Browse files Browse the repository at this point in the history
…ognition start/stop, Config versioning, Bump version
  • Loading branch information
PaciStardust committed Jan 9, 2023
1 parent 22f5ade commit 0a0fcbd
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 78 deletions.
199 changes: 150 additions & 49 deletions OscMultitool/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -52,9 +53,11 @@ static Config()
}
catch
{
Data = GetDefaultConfig();
Data = new();
}

UpdateConfig(Data);

if (!Directory.Exists(ResourcePath))
MessageBox.Show("Failed to create config directory, please check your antivirus and your permissions", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Expand All @@ -66,7 +69,7 @@ public static void SaveConfig()
{
try
{
File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(Data ?? new(), Formatting.Indented));
File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(Data ?? new(), Formatting.Indented), Encoding.UTF8);
Logger.PInfo("Saved config file at " + ConfigPath);
}
catch (Exception e)
Expand Down Expand Up @@ -103,51 +106,105 @@ public static string GetVersion()
/// <summary>
/// This exists as newtonsoft seems to have an issue with my way of creating a default config
/// </summary>
private static ConfigModel GetDefaultConfig()
private static void UpdateConfig(ConfigModel config)
{
var config = new ConfigModel();

config.Speech.NoiseFilter.AddRange(new List<string>()
if (config.ConfigVersion < 1) //contains ifs to ensure old configs dont get these again
{
"the",
"and",
"einen"
});
if (config.Speech.NoiseFilter.Count == 0)
{
config.Speech.NoiseFilter.AddRange(new List<string>()
{
"the",
"and",
"einen"
});
}

config.Debug.LogFilter.AddRange(new List<string>()
{
"/angular",
"/grounded",
"/velocity",
"/upright",
"/voice",
"/viseme",
"/gesture",
"_angle",
"_stretch"
});

config.Speech.Replacements.AddRange(new List<ReplacementModel>()
if (config.Debug.LogFilter.Count == 0)
{
config.Debug.LogFilter.AddRange(new List<string>()
{
"/angular",
"/grounded",
"/velocity",
"/upright",
"/voice",
"/viseme",
"/gesture",
"_angle",
"_stretch"
});
}

if (config.Speech.Replacements.Count == 0)
{
config.Speech.Replacements.AddRange(new List<ReplacementModel>()
{
new("exclamation mark", "!"),
new("question mark", "?"),
new("colon", ":"),
new("semicolon", ";"),
new("open parenthesis", "("),
new("closed parenthesis", ")"),
new("open bracket", "("),
new("closed bracket", ")"),
new("minus", "-"),
new("plus", "+"),
new("slash", "/"),
new("backslash", "\\"),
new("hashtag", "#"),
new("asterisk", "*")
});
}
}

if (config.ConfigVersion < 2)
{
new("exclamation mark", "!"),
new("question mark", "?"),
new("colon", ":"),
new("semicolon", ";"),
new("open parenthesis", "("),
new("closed parenthesis", ")"),
new("open bracket", "("),
new("closed bracket", ")"),
new("minus", "-"),
new("plus", "+"),
new("slash", "/"),
new("backslash", "\\"),
new("hashtag", "#"),
new("asterisk", "*")
});

config.Speech.Shortcuts.Add(new("box toggle", "[osc] [/avatar/parameters/ToolEnableBox [b]true \"self \"]"));

return config;
config.Speech.Shortcuts.Add(new("box toggle", "[osc] [/avatar/parameters/ToolEnableBox [b]true \"self\"]"));

config.Api.Presets.AddRange(new List<ApiPresetModel>()
{
new ApiPresetModel()
{
Name = "Example - Azure to DE",
TargetUrl = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=de",
ResultField = "text",
SentData = @"[{""Text"" : ""[T]""}]",
ContentType = "application/json",
HeaderValues = new()
{
{ "Ocp-Apim-Subscription-Key", "[YOUR KEY]" },
{ "Ocp-Apim-Subscription-Region", "[YOUR REGION]" }
}
},

new ApiPresetModel()
{
Name = "Example - Azure Recognition",
TargetUrl = "https://northeurope.stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=en-US",
ResultField = "Display Text",
SentData = string.Empty,
ContentType = "audio/wav; codecs=audio/pcm; samplerate=16000",
HeaderValues = new()
{
{ "Ocp-Apim-Subscription-Key", "[YOUR KEY]" },
{ "Accept", "true" }
}
},

new ApiPresetModel()
{
Name = "Example - DeepL to DE",
TargetUrl = "https://api-free.deepl.com/v2/translate",
ResultField = "text",
SentData = "text=[T]&target_lang=DE",
ContentType = "application/x-www-form-urlencoded",
Authorization = "DeepL-Auth-Key [YOUR KEY]"
}
});
}

config.ConfigVersion = 2;
}

/// <summary>
Expand Down Expand Up @@ -198,6 +255,8 @@ private static string GetActualModelFolder(string folderName)
/// </summary>
public 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();
Expand Down Expand Up @@ -526,22 +585,64 @@ public override string ToString()
public class ApiPresetModel
{
public string Name { get; set; } = "Example Preset";
public string PostUrl { get; set; } = "https://example.net";
public string JsonData { get; set; } = @"{""data"" : ""[T]""}";
public string SentData { get; set; } = @"{""data"" : ""[T]""}";
public Dictionary<string, string> HeaderValues { get; set; } = new();
public string ContentType { get; set; } = string.Empty;
public string ContentType { get; set; } = "application/json";
public string ResultField { get; set; } = "result";

public string TargetUrl
{
get { return _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 { return _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 { return _connectionTimeout; }
set { _connectionTimeout = MinMax(value, 25, 60000); }
}
private int _connectionTimeout = 3000;

public string FullTargetUrl() => _fullTargetUrl;
public AuthenticationHeaderValue? AuthenticationHeader() => _authenticationHeader;

public bool IsValid()
=> !string.IsNullOrWhiteSpace(PostUrl)
&& !string.IsNullOrWhiteSpace(JsonData)
&& !string.IsNullOrWhiteSpace(ResultField);
=> !string.IsNullOrWhiteSpace(TargetUrl)
&& !string.IsNullOrWhiteSpace(SentData)
&& !string.IsNullOrWhiteSpace(ResultField)
&& !string.IsNullOrWhiteSpace(ContentType);
}

public class CounterModel
Expand Down
4 changes: 2 additions & 2 deletions OscMultitool/Hoscy.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<UseWPF>true</UseWPF>
<ApplicationIcon>Resources\hoscy_circle.ico</ApplicationIcon>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyVersion>0.5.8</AssemblyVersion>
<FileVersion>0.5.8</FileVersion>
<AssemblyVersion>0.6</AssemblyVersion>
<FileVersion>0.6</FileVersion>
<RepositoryUrl>https://github.com/PaciStardust/HOSCY</RepositoryUrl>
<PackageProjectUrl>https://github.com/PaciStardust/HOSCY</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down
19 changes: 13 additions & 6 deletions OscMultitool/Services/Api/ApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@ public bool LoadPreset(Config.ApiPresetModel preset)
if (_preset == null || !_preset.IsValid())
return null;

AddHeaders(content);
var requestMessage = new HttpRequestMessage(HttpMethod.Post, _preset.TargetUrl)
{
Content = content
};

AddHeaders(requestMessage);

var jsonIn = await HoscyClient.RequestAsync(_preset.PostUrl, content, _preset.ConnectionTimeout);
var jsonIn = await HoscyClient.SendAsync(requestMessage, _preset.ConnectionTimeout);

if (jsonIn == null)
return null;
Expand All @@ -60,24 +65,26 @@ public bool LoadPreset(Config.ApiPresetModel preset)
public async Task<string?> SendText(string text)
{
if (_preset == null) return string.Empty;
var jsonOut = ReplaceToken(_preset.JsonData, "[T]", text);
var jsonOut = ReplaceToken(_preset.SentData, "[T]", text);

if (_preset.JsonData == jsonOut)
if (_preset.SentData == jsonOut)
{
Logger.Error("Unable to send data to data to API as JSON contains no token, have you made sure the JSON option contains \"[T]\"?");
return string.Empty;
}

return await Send(new StringContent(jsonOut, Encoding.UTF8, "application/json"));
return await Send(new StringContent(jsonOut, Encoding.UTF8, _preset.ContentType));
}
#endregion

#region Utils
private void AddHeaders(HttpContent content)
private void AddHeaders(HttpRequestMessage content)
{
if (_preset == null)
return;

content.Headers.Authorization = _preset.AuthenticationHeader();

foreach (var headerInfo in _preset.HeaderValues)
{
if (!content.Headers.TryAddWithoutValidation(headerInfo.Key, headerInfo.Value))
Expand Down
25 changes: 12 additions & 13 deletions OscMultitool/Services/Api/HoscyClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,28 @@ static HoscyClient()

#region Requests
/// <summary>
/// Either does a post or get
/// <br/><b>THESE WILL LAG ON SOME SYSTEMS, IF YOU KNOW WHY PLEASE LET ME KNOW</b>
/// Wrapper for sending with the HTTPClient
/// </summary>
/// <param name="url">Target URL</param>
/// <param name="content">Content, if this is null, a get will be performed</param>
/// <param name="timeout">Timeout in ms</param>
/// <returns>Response, if null this failed</returns>
public static async Task<string?> RequestAsync(string url, HttpContent? content = null, int timeout = 5000, bool notify = true)
/// <param name="requestMessage">RequestMessage to send</param>
/// <param name="timeout">Request timeout</param>
/// <param name="notify">Notification window on error?</param>
/// <returns>JSON response on success</returns>
public static async Task<string?> SendAsync(HttpRequestMessage requestMessage, int timeout = 5000, bool notify = true)
{
var identifier = GetRequestIdentifier();

var startTime = DateTime.Now;
Logger.Debug($"{(content == null ? "Getting from" : "Posting to")} {url} ({identifier})");
Logger.Debug($"Sending {requestMessage.Method} to {requestMessage.RequestUri} ({identifier})");
try
{
var cts = new CancellationTokenSource(timeout);
var response = content == null
? await _client.GetAsync(url, cts.Token)
: await _client.PostAsync(url, content, cts.Token);
var response = await _client.SendAsync(requestMessage, cts.Token);

var jsonIn = await response.Content.ReadAsStringAsync(cts.Token);

if (!response.IsSuccessStatusCode)
{
Logger.Error($"Request {identifier} has received status code \"{response.StatusCode}\"" + (string.IsNullOrWhiteSpace(jsonIn) ? "" : $" ({jsonIn})"), notify:notify);
Logger.Error($"Request {identifier} has received status code \"{response.StatusCode}\" ({(int)response.StatusCode})" + (string.IsNullOrWhiteSpace(jsonIn) ? "" : $" ({jsonIn})"), notify: notify);
return null;
}

Expand Down Expand Up @@ -79,7 +76,9 @@ private static async Task CheckForUpdatesInternal()
var currVer = Config.GetVersion();
Logger.PInfo("Attempting to check for newest HOSCY version, current is " + currVer);

var res = await RequestAsync(Config.GithubLatest, notify: false);
var requestMessage = new HttpRequestMessage(HttpMethod.Get, Config.GithubLatest);

var res = await SendAsync(requestMessage, notify: false);
if (res == null)
{
Logger.Warning("Failed to grab version number from GitHub");
Expand Down
2 changes: 2 additions & 0 deletions OscMultitool/Services/Speech/Recognition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public static bool StartRecognizer()
return false;
}

Config.SaveConfig(); //Saving to ensure it doesnt wipe when crashing
Logger.PInfo("Attempting to start recognizer...");
if (!_recognizer.Start())
{
Expand Down Expand Up @@ -60,6 +61,7 @@ public static void StopRecognizer()
return;
}

Config.SaveConfig(); //Saving to ensure it doesnt wipe when crashing
_recognizer.Stop();
_recognizer = null;
TriggerRecognitionChanged();
Expand Down
2 changes: 1 addition & 1 deletion OscMultitool/Services/Speech/TextProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private static bool ExecuteCommands(string message)
public static string? ExtractFromJson(string name, string json)
{
string regstring = name + @""" *: *""(?<value>([^""\\]|\\.)*)""";
var regex = new Regex(regstring, RegexOptions.IgnoreCase);
var regex = new Regex(regstring, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

var result = regex.Match(json)?.Groups["value"].Value ?? null;
return string.IsNullOrWhiteSpace(result) ? null : Regex.Unescape(result);
Expand Down
Loading

0 comments on commit 0a0fcbd

Please sign in to comment.