Compare commits
3 Commits
10a6babce9
...
39d74e5d71
Author | SHA1 | Date | |
---|---|---|---|
39d74e5d71 | |||
86dc3bbb0e | |||
7a11a3512f |
@ -1,16 +1,20 @@
|
||||
using EmojiCSharp;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using EmojiCSharp;
|
||||
using TwitchLib.Client.Models;
|
||||
|
||||
namespace TTSMe;
|
||||
|
||||
public static class ExtensionMethods {
|
||||
private static byte[] ToBytes(this string str) => Encoding.UTF8.GetBytes(str);
|
||||
private static string ToHexString(this byte[] bytes) => Convert.ToHexString(bytes);
|
||||
private static string ToSHA256HashedString(this string str) => SHA256.HashData(str.ToBytes()).ToHexString();
|
||||
|
||||
internal static string? GetStoredVoice(this ChatMessage chatMessage) => Voices.Instance().GetVoice(chatMessage.Username);
|
||||
internal static bool HasStoredVoice(this ChatMessage chatMessage) => Voices.Instance().HasVoice(chatMessage.Username);
|
||||
// parse out all emojis into their full names
|
||||
internal static string GetMessageText(this ChatMessage chatMessage) =>
|
||||
EmojiParser.ParseToAliases(chatMessage.Message)
|
||||
.Replace(":", " colon ")
|
||||
.Replace("_", " underscore ");
|
||||
internal static string GetMessageText(this ChatMessage chatMessage) => EmojiParser.ParseToAliases(chatMessage.Message).Replace(":", " colon ").Replace("_", " underscore ");
|
||||
private static string GetMessageHash(this ChatMessage chatMessage) => chatMessage.GetMessageText().ToSHA256HashedString();
|
||||
internal static string GetAudioFilePath(this ChatMessage chatMessage) => Path.Combine(TTSClient.AudioBasePath, $"{chatMessage.GetStoredVoice()!}-{chatMessage.GetMessageHash()}.mp3");
|
||||
|
||||
internal static TextToSpeechRequest ToTTSRequest(this ChatMessage chatMessage) => new(chatMessage.GetMessageText(), chatMessage.GetStoredVoice()!);
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json.Serialization;
|
||||
using LibVLCSharp.Shared;
|
||||
using TwitchLib.Client.Models;
|
||||
@ -14,14 +13,12 @@ public static class TTSClient {
|
||||
},
|
||||
BaseAddress = new Uri("https://api.openai.com")
|
||||
};
|
||||
private const string basePath = "C:/data/twitch/tts";
|
||||
public const string AudioBasePath = @"C:\data\twitch\tts";
|
||||
|
||||
public static async Task<string> GenerateSpeech(ChatMessage chatMessage) {
|
||||
public static async Task GenerateSpeech(ChatMessage chatMessage) {
|
||||
Console.WriteLine($"Generating speech as {chatMessage.GetAudioFilePath()} for {chatMessage.Username}: {chatMessage.Message}");
|
||||
HttpResponseMessage response = await httpClient.PostAsJsonAsync("v1/audio/speech", chatMessage.ToTTSRequest());
|
||||
byte[] bytes = await response.Content.ReadAsByteArrayAsync();
|
||||
string outputPath = Path.Combine(basePath, $"{Guid.NewGuid()}.mp3");
|
||||
await File.WriteAllBytesAsync(outputPath, bytes);
|
||||
return outputPath;
|
||||
await File.WriteAllBytesAsync(chatMessage.GetAudioFilePath(), await response.Content.ReadAsByteArrayAsync());
|
||||
}
|
||||
|
||||
public static async Task PlaySpeech(string path) {
|
||||
|
@ -6,6 +6,11 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<PackageId>TwitchUtils.TTSMe</PackageId>
|
||||
<Title>TTSMe</Title>
|
||||
<Authors>Nathan Windisch</Authors>
|
||||
<PackageProjectUrl>https://git.natfan.io/n/TwitchUtils</PackageProjectUrl>
|
||||
<RepositoryUrl>https://git.natfan.io/n/TwitchUtils</RepositoryUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -34,6 +34,7 @@ public abstract class TtsMeCommand {
|
||||
case "set" when voices.IsVoice(username, voice): return $"ttsme voice for '{username}' is already set to '{voice}'.";
|
||||
case "set": voices.SetVoice(username, voice); return $"Changing ttsme for {username} to '{voice}'";
|
||||
|
||||
// TODO: Get OptOut working so that it doesn't opt you back in when next chatting
|
||||
case "optout": voices.RemoveVoice(username); return $"Opting {username} out of ttsme, their voice will no longer be heard by the masses (and me!)";
|
||||
|
||||
default: return UsageMessage;
|
||||
|
@ -21,7 +21,7 @@ public class Voices {
|
||||
public static async Task ProcessVoiceMessage(ChatMessage chatMessage) {
|
||||
string? voice = chatMessage.GetStoredVoice();
|
||||
if (voice is null) return;
|
||||
string filePath = await TTSClient.GenerateSpeech(chatMessage);
|
||||
await TTSClient.PlaySpeech(filePath);
|
||||
if (!File.Exists(chatMessage.GetAudioFilePath())) await TTSClient.GenerateSpeech(chatMessage);
|
||||
await TTSClient.PlaySpeech(chatMessage.GetAudioFilePath());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user