From 21bc3bd7757736f062012fe342551cec080cde7d Mon Sep 17 00:00:00 2001 From: sim1222 Date: Sat, 5 Aug 2023 23:14:16 +0900 Subject: [PATCH] add DictionaryDB --- Elementary/Audio/AudioManager.cs | 21 ++++-- Elementary/Audio/SozaiAPI.cs | 9 ++- Elementary/Commands/MessageCommands.cs | 39 ++++++++++- Elementary/Config/Configuration.cs | 18 +++++ Elementary/Dictionary/DictionaryDB.cs | 84 ++++++++++++++++++++++++ Elementary/Dictionary/EmojiDictionary.cs | 46 +++++++++++++ Elementary/Elementary.csproj | 37 ++++++----- Elementary/Program.cs | 33 ++++++++-- Elementary/appsettings.json | 9 +++ Elementary/nlog.config | 16 ++--- 10 files changed, 271 insertions(+), 41 deletions(-) create mode 100644 Elementary/Dictionary/DictionaryDB.cs create mode 100644 Elementary/Dictionary/EmojiDictionary.cs diff --git a/Elementary/Audio/AudioManager.cs b/Elementary/Audio/AudioManager.cs index ac398c9..1f797c3 100644 --- a/Elementary/Audio/AudioManager.cs +++ b/Elementary/Audio/AudioManager.cs @@ -4,6 +4,7 @@ using System.Text.RegularExpressions; using Discord; using Discord.Audio; using Discord.WebSocket; +using Elementary.Dictionary; using ManagedBass; using Microsoft.Extensions.DependencyInjection; using NAudio.Wave; @@ -24,6 +25,8 @@ public class AudioManager private AudioConverter _audioConverter; private PlaybackQueue _playbackQueue; + private EmojiDictionary _emojiDictionary; + private DictionaryDB _dictionaryDB; // private AudioMixer _audioMixer; private ILogger _logger; @@ -31,13 +34,15 @@ public class AudioManager public bool isConnected; public AudioManager(IServiceProvider services, DiscordSocketClient client, SozaiAPI sozaiApi, - VoicevoxAPI voicevoxApi) + VoicevoxAPI voicevoxApi, EmojiDictionary emojiDictionary, DictionaryDB dictionaryDB) { _services = services; _client = client; _sozaiAPI = sozaiApi; _voicevoxAPI = voicevoxApi; _audioConverter = new(); + _emojiDictionary = emojiDictionary; + _dictionaryDB = dictionaryDB; _logger = LogManager.GetCurrentClassLogger(); } @@ -72,9 +77,11 @@ public class AudioManager _audioClient.Dispose(); } - public async Task PlayAudio(string path) + public async Task PlayAudio(string path, float volume = 1.0f) { - await using var wave = _audioConverter.CreateStreamFromFilePath(path, 0.15f); + float maxVolume = 0.15f; + + await using var wave = _audioConverter.CreateStreamFromFilePath(path, volume * maxVolume); _logger.Log(LogLevel.Info, $"Playing {path} {wave.Length} bytes"); @@ -88,7 +95,13 @@ public class AudioManager if (text.Contains("```")) text = "コードブロック"; if (text.StartsWith("!") || text.StartsWith(".")) return; text = Regex.Replace(text, @"https?://[\w/:%#\$&\?\(\)~\.=\+\-]+", "URL"); - text = Regex.Replace(text, @"<:[\w]+:[\d]+>", m => m.Value.Split(":")[1]); + + text = Regex.Replace(text, @"<:[\w]+:[\d]+>", m => m.Value.Split(":")[1]); // <:emoji:123456789> -> emoji + text = Regex.Replace(text, @"", m => m.Value.Split(":")[1]); // <:emoji:123456789> -> emoji + + text = _dictionaryDB.Replace(text); + + text = _emojiDictionary.Replace(text); float volume = 0.12f; diff --git a/Elementary/Audio/SozaiAPI.cs b/Elementary/Audio/SozaiAPI.cs index a671a27..ad77ae0 100644 --- a/Elementary/Audio/SozaiAPI.cs +++ b/Elementary/Audio/SozaiAPI.cs @@ -7,7 +7,6 @@ public class SozaiAPI { private ILogger _logger; - private Uri AssetsInfoUrl = new("https://r2.sim1222.com/sozai/index.json"); private Asset[] Assets; private class Asset @@ -32,9 +31,9 @@ public class SozaiAPI _logger = LogManager.GetCurrentClassLogger(); } - public async Task Setup() + public async Task Setup(string url) { - var response = await _client.GetAsync(AssetsInfoUrl); + var response = await _client.GetAsync(url); var stream = await response.Content.ReadAsStreamAsync(); Assets = await JsonSerializer.DeserializeAsync(stream); @@ -47,10 +46,10 @@ public class SozaiAPI var asset = Assets.FirstOrDefault(asset => asset.names.Contains(name)); if (asset == null) return null; - Console.WriteLine($"Requested {asset.names[0]}"); + _logger.Info($"Requested {asset.names[0]}"); var response = await _client.GetAsync(asset.url); - Console.WriteLine($"Got response {response.StatusCode}"); + _logger.Info($"Got response {response.StatusCode}"); var stream = await response.Content.ReadAsStreamAsync(); return stream; } diff --git a/Elementary/Commands/MessageCommands.cs b/Elementary/Commands/MessageCommands.cs index f5ecf80..495ba2d 100644 --- a/Elementary/Commands/MessageCommands.cs +++ b/Elementary/Commands/MessageCommands.cs @@ -1,6 +1,7 @@ using Discord; using Discord.Commands; using Elementary.Audio; +using Elementary.Dictionary; namespace Elementary.Commands; @@ -9,12 +10,15 @@ public class MessageCommands : ModuleBase private AudioManager _audioManager; private readonly IServiceProvider _serviceProvider; private readonly CommandService _commandService; + private DictionaryDB _dictionaryDB; - public MessageCommands(AudioManager audioManager, CommandService commandService, IServiceProvider serviceProvider) + public MessageCommands(AudioManager audioManager, CommandService commandService, IServiceProvider serviceProvider, + DictionaryDB dictionaryDB) { _audioManager = audioManager; _commandService = commandService; _serviceProvider = serviceProvider; + _dictionaryDB = dictionaryDB; } [Command("help")] @@ -68,13 +72,44 @@ public class MessageCommands : ModuleBase [Summary("Plays audio from a file.")] public async Task PlayAsync([Remainder] [Summary("The path to the file")] string path) { + path = path.Trim('"'); await _audioManager.PlayAudio(path); } - + [Command("stop", RunMode = RunMode.Async)] [Summary("Stops playing audio.")] public async Task StopAsync() { await _audioManager.StopAudio(); } + + [Command("add", RunMode = RunMode.Async)] + [Summary("Adds a word to the dictionary.")] + public Task AddAsync( [Summary("From Surface")] string surface, [Summary("To Pronunciation")]string pronunciation) + { + _dictionaryDB.Add(surface, pronunciation); + return ReplyAsync($"Added {surface} -> {pronunciation}"); + } + + [Command("del", RunMode = RunMode.Async)] + [Summary("Deletes a word from the dictionary.")] + public Task DeleteAsync([Summary("From Surface")] string surface) + { + _dictionaryDB.Remove(surface); + return ReplyAsync($"Removed {surface}"); + } + + [Command("list", RunMode = RunMode.Async)] + [Summary("Lists all words in the dictionary.")] + public Task ListAsync() + { + var dict = _dictionaryDB.GetAll(); + string result = "```\n"; + foreach (var item in dict) + { + result += $"{item.Key} -> {item.Value}\n"; + } + result += "```"; + return ReplyAsync(result); + } } \ No newline at end of file diff --git a/Elementary/Config/Configuration.cs b/Elementary/Config/Configuration.cs index 6b108a2..6dc7d72 100644 --- a/Elementary/Config/Configuration.cs +++ b/Elementary/Config/Configuration.cs @@ -7,6 +7,24 @@ namespace Elementary.Config; public class AppSettings { public DiscordSettings DiscordSettings { get; set; } + public SozaiSettings SozaiSettings { get; set; } + public EmojiSettings EmojiSettings { get; set; } + public VoicevoxSettings VoicevoxSettings { get; set; } +} + +public class VoicevoxSettings +{ + public string Url { get; set; } +} + +public class EmojiSettings +{ + public string DictionaryPath { get; set; } +} + +public class SozaiSettings +{ + public string Url { get; set; } } public class DiscordSettings diff --git a/Elementary/Dictionary/DictionaryDB.cs b/Elementary/Dictionary/DictionaryDB.cs new file mode 100644 index 0000000..c5b2990 --- /dev/null +++ b/Elementary/Dictionary/DictionaryDB.cs @@ -0,0 +1,84 @@ +using System.Text.RegularExpressions; +using LiteDB; +using NLog; + +namespace Elementary.Dictionary; + +public class DictionaryDB +{ + private LiteDatabase _db; + private ILogger _logger; + + private class DictionaryItem + { + public string Surface { get; set; } + public string Pronunciation { get; set; } + public int Priority { get; set; } + } + + public DictionaryDB() + { + _logger = LogManager.GetCurrentClassLogger(); + } + + public async Task Setup() + { + _db = new LiteDatabase("dictionary.db"); + } + + public void Add(string surface, string pronunciation, int priority = 5) + { + surface = Regex.Replace(surface, @"<:[\w]+:[\d]+>", m => m.Value.Split(":")[1]); // <:emoji:123456789> -> emoji + surface = Regex.Replace(surface, @"", m => m.Value.Split(":")[1]); // <:emoji:123456789> -> emoji + + var collection = _db.GetCollection("dictionary"); + + // Remove existing items + collection.DeleteMany(item => item.Surface == surface); + + collection.Insert(new DictionaryItem + { + Surface = surface, + Pronunciation = pronunciation, + Priority = priority + }); + _logger.Info($"Added {surface} -> {pronunciation}"); + } + + public void Remove(string surface) + { + surface = Regex.Replace(surface, @"<:[\w]+:[\d]+>", m => m.Value.Split(":")[1]); // <:emoji:123456789> -> emoji + surface = Regex.Replace(surface, @"", m => m.Value.Split(":")[1]); // <:emoji:123456789> -> emoji + + var collection = _db.GetCollection("dictionary"); + collection.DeleteMany(item => item.Surface == surface); + _logger.Info($"Removed {surface}"); + } + + public string Replace(string text) + { + var collection = _db.GetCollection("dictionary"); + var items = collection.FindAll().OrderByDescending(item => item.Priority); + + foreach (var item in items) + { + text = text.Replace(item.Surface, item.Pronunciation); + } + + return text; + } + + public Dictionary GetAll() + { + var collection = _db.GetCollection("dictionary"); + var items = collection.FindAll(); + + var dict = new Dictionary(); + foreach (var item in items) + { + dict.Add(item.Surface, item.Pronunciation); + } + + return dict; + } +} \ No newline at end of file diff --git a/Elementary/Dictionary/EmojiDictionary.cs b/Elementary/Dictionary/EmojiDictionary.cs new file mode 100644 index 0000000..1ce3e8e --- /dev/null +++ b/Elementary/Dictionary/EmojiDictionary.cs @@ -0,0 +1,46 @@ + +using System.Text.Json; +using Microsoft.Extensions.Logging; +using NLog; +using ILogger = NLog.ILogger; + +namespace Elementary.Dictionary; + +public class EmojiDictionary +{ + private Dictionary _dict; + private readonly ILogger _logger; + + private class DictionaryItem + { + public string[] keywords { get; set; } + public string short_name { get; set; } + public string group { get; set; } + public string subgroup { get; set; } + } + + public EmojiDictionary() + { + _logger = LogManager.GetCurrentClassLogger(); + } + + public async Task Setup(string Path) + { + using StreamReader file = new(Path); + _dict = await JsonSerializer.DeserializeAsync>(file.BaseStream); + _logger.Info($"Loaded {_dict.Count} emoji"); + } + + public string Replace(string text) + { + string[] ignoreKeys = {"、", "。"}; + + foreach (var (key, value) in _dict) + { + if (ignoreKeys.Contains(key)) continue; + text = text.Replace(key, value.short_name); + } + + return text; + } +} \ No newline at end of file diff --git a/Elementary/Elementary.csproj b/Elementary/Elementary.csproj index b2edd8c..65146ad 100644 --- a/Elementary/Elementary.csproj +++ b/Elementary/Elementary.csproj @@ -17,20 +17,21 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -44,14 +45,18 @@ Always - Always + Always - Always + Always + Always + + Always + diff --git a/Elementary/Program.cs b/Elementary/Program.cs index 257914c..5de73fa 100644 --- a/Elementary/Program.cs +++ b/Elementary/Program.cs @@ -6,6 +6,7 @@ using Discord.Commands; using Discord.WebSocket; using Elementary.Audio; using Elementary.Commands; +using Elementary.Dictionary; using ManagedBass; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -27,10 +28,23 @@ public class Program private Handler _handler; private SozaiAPI _sozaiAPI; private VoicevoxAPI _voicevoxAPI; + private EmojiDictionary _emojiDictionary; + private DictionaryDB _dictionaryDB; - public static void Main(string[] args) + public static async Task Main(string[] args) { - new Program().Setup().GetAwaiter().GetResult(); + while (true) + { + try + { + await new Program().Setup(); + await Task.Delay(-1); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } } private async Task Setup() @@ -57,6 +71,8 @@ public class Program .AddSingleton() .AddTransient() .AddSingleton() + .AddSingleton() + .AddSingleton() .BuildServiceProvider(); _logger = LogManager.GetCurrentClassLogger(); @@ -64,7 +80,10 @@ public class Program _sozaiAPI = _services.GetRequiredService(); _voicevoxAPI = _services.GetRequiredService(); - _handler = new Handler(_client, _commands, _services, _services.GetRequiredService(), + _emojiDictionary = _services.GetRequiredService(); + _dictionaryDB = _services.GetRequiredService(); + + _handler = new(_client, _commands, _services, _services.GetRequiredService(), _services.GetRequiredService()); _client.Log += Log; @@ -73,8 +92,10 @@ public class Program // Bass.Init(-1, 44100, DeviceInitFlags.NoSpeakerAssignment, IntPtr.Zero); await _handler.Setup(); - await _sozaiAPI.Setup(); - await _voicevoxAPI.Setup("http://localhost:50021"); + await _sozaiAPI.Setup(configuration.AppSettings.SozaiSettings.Url); + await _voicevoxAPI.Setup(configuration.AppSettings.VoicevoxSettings.Url); + await _emojiDictionary.Setup(configuration.AppSettings.EmojiSettings.DictionaryPath); + await _dictionaryDB.Setup(); await _client.LoginAsync(TokenType.Bot, configuration.AppSettings.DiscordSettings.Token); await _client.StartAsync(); await _client.SetActivityAsync(new Game("!join")); @@ -84,7 +105,7 @@ public class Program // await _client.StopAsync(); // await _client.StartAsync(); // }; - + _client.UserVoiceStateUpdated += async (user, before, after) => { if (user.Id != _client.CurrentUser.Id) return; diff --git a/Elementary/appsettings.json b/Elementary/appsettings.json index 0e85222..94071a3 100644 --- a/Elementary/appsettings.json +++ b/Elementary/appsettings.json @@ -9,6 +9,15 @@ "AppSettings": { "DiscordSettings": { "Token": "MTEzMDAzMjkxMTQzMzg1OTE5Mw.G8yVqt.HrC65f0t4dvZQIZ7iER4CV70pLvhAl8PIyknSs" + }, + "VoicevoxSettings": { + "Url": "http://localhost:50021" + }, + "SozaiSettings": { + "Url": "https://r2.sim1222.com/sozai/index.json" + }, + "EmojiSettings": { + "DictionaryPath": "emoji-ja\\data\\emoji_ja.json" } } } \ No newline at end of file diff --git a/Elementary/nlog.config b/Elementary/nlog.config index c1bdf66..d209ac8 100644 --- a/Elementary/nlog.config +++ b/Elementary/nlog.config @@ -4,7 +4,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogFile="c:\temp\console-example-internal.log" - internalLogLevel="Info" > + internalLogLevel="Info"> @@ -14,17 +14,17 @@ - - - - - + layout="${longdate} [${level:uppercase=true:padding=-4}] ${logger} | ${message} ${all-event-properties} ${exception:format=tostring}"> + + + + + - + \ No newline at end of file