using System.Collections.Concurrent; using System.Data; using System.Diagnostics; using System.Net; using System.Reflection.Metadata.Ecma335; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using System.Timers; using Newtonsoft.Json; namespace placeholdervo { public partial class Program { [GeneratedRegex("^[^a-zA-Z0-9'\"]")] private static partial Regex TextLine(); public static Config conf; private static string workingDir = "./"; private static ConcurrentQueue scriptFragmentFiles = new ConcurrentQueue(); private static CancellationToken scriptFileCancellationToken; private static async void webcall() { var hc = new HttpClient(){ BaseAddress = new Uri(conf.speech_service)}; while(true) { while(!scriptFragmentFiles.IsEmpty) { string scriptFragment; scriptFragmentFiles.TryDequeue(out scriptFragment); if(scriptFragment == null) continue; Console.WriteLine(scriptFragment); HttpContent fileStreamContent = new StreamContent(File.OpenRead(scriptFragment)); using (var formData = new MultipartFormDataContent()) { formData.Add(fileStreamContent, "file1", "file1"); var response = await hc.PostAsync("/speak", formData); if (!response.IsSuccessStatusCode) { Console.Error.WriteLine($"{response.StatusCode} - {response.ReasonPhrase} - {await response.Content.ReadAsStringAsync()}"); } else { var resp = string.Join(", ", JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync())); Console.WriteLine($"success; {resp}."); if(resp != null) { scriptFragmentVoiceFiles[resp] = scriptFragment; Console.WriteLine("Ditching script fragment file."); File.Delete(scriptFragment); } } } System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); } if(scriptFileCancellationToken.IsCancellationRequested && scriptFragmentFiles.IsEmpty) { return; } } } private static ConcurrentDictionary scriptFragmentVoiceFiles = new ConcurrentDictionary(); private static async void filePickup() { while(true) { while(!scriptFragmentVoiceFiles.IsEmpty) { var files = Directory.GetFiles(conf.sync_dropoff); Console.WriteLine($"files listed: {string.Join(", ", files)}"); Console.WriteLine($"hoping for: {string.Join(", ", scriptFragmentVoiceFiles.Keys)}"); // Console.WriteLine($"sanity check: first listed file: {Path.GetFileName(files.FirstOrDefault())}"); // Console.WriteLine($"sanity check: first key: {scriptFragmentVoiceFiles.Keys.FirstOrDefault()}"); // Console.WriteLine($"sanity check: first value: {scriptFragmentVoiceFiles[scriptFragmentVoiceFiles.Keys.FirstOrDefault()]}"); var audioFile = files.FirstOrDefault(f => scriptFragmentVoiceFiles.ContainsKey(Path.GetFileName(f))); if(!string.IsNullOrWhiteSpace(audioFile)) { Console.WriteLine($"found {audioFile}"); try { var bareAudioFile = Path.GetFileName(audioFile); var destFile = scriptFragmentVoiceFiles[bareAudioFile]; destFile = Path.GetFileNameWithoutExtension(destFile) + ".wav"; destFile = Path.Combine(workingDir, destFile); File.Move(audioFile, destFile); if(!scriptFragmentVoiceFiles.Remove(bareAudioFile, out string throwaway)) { Console.WriteLine($"failed to remove {bareAudioFile}"); } } catch(Exception e) { Console.Error.WriteLine(e.Message); } } System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); } if(scriptFileCancellationToken.IsCancellationRequested) { return; } System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1)); } } public static async Task Main(string[] args) { conf = JsonConvert.DeserializeObject( File.ReadAllText( AppDomain.CurrentDomain.BaseDirectory + "appsettings.json")) ?? new Config(); var scriptPath = args?.FirstOrDefault(); if(string.IsNullOrWhiteSpace(scriptPath)) scriptPath = "./script.txt"; workingDir = Path.GetDirectoryName(scriptPath); var cancelSource = new CancellationTokenSource(); scriptFileCancellationToken = cancelSource.Token; var apiCallThread = new Thread(new ThreadStart(webcall)); apiCallThread.Start(); var fileRetrieveThread = new Thread(new ThreadStart(filePickup)); fileRetrieveThread.Start(); var lines = File.ReadAllLines(scriptPath).Where(l => !TextLine().IsMatch(l)) .Append("\n").Append("\n"); //pad out file so my tactic for separating doesn't fall off the end of the file var lineCountMagnitude = (int)Math.Log10(lines.Count()); var runningSavedLines = new List(); var completeSavedLines = new List(); var iteration = 0; foreach(var l in lines) { if(string.IsNullOrWhiteSpace(l)) { if(runningSavedLines.Any(line => !string.IsNullOrWhiteSpace(line))) { ++iteration; //x.ToString("D2") should format x with minimum 2 digits, padded left var scriptFragment = $"script{iteration.ToString($"D{lineCountMagnitude}")}.txt"; File.WriteAllLines(scriptFragment, runningSavedLines); scriptFragmentFiles.Enqueue(scriptFragment); completeSavedLines.AddRange(runningSavedLines); } runningSavedLines = []; } else { runningSavedLines.Add(l); } } var scriptStripped = $"script{0.ToString($"D{lineCountMagnitude}")}.txt"; File.WriteAllLines(scriptStripped, completeSavedLines); scriptFragmentFiles.Enqueue(scriptStripped); cancelSource.Cancel(); Console.WriteLine("http client \"cancelled\"."); while(apiCallThread.ThreadState != System.Threading.ThreadState.Stopped) { Console.WriteLine("thread still running. waiting."); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); } Console.WriteLine($"api call thread done ({apiCallThread.ThreadState})."); while(fileRetrieveThread.ThreadState != System.Threading.ThreadState.Stopped) { Console.WriteLine("fileRetrieveThread still running. waiting."); System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); } Console.WriteLine($"fileRetrieveThread done ({fileRetrieveThread.ThreadState}). kbai"); } } }