works mostly, depends on powershell speech service

This commit is contained in:
adam 2024-07-14 17:20:34 -04:00
parent d2c2da6808
commit bc9d4f8119
5 changed files with 202 additions and 28 deletions

4
.gitignore vendored
View File

@ -376,4 +376,6 @@ FodyWeavers.xsd
# Local History for Visual Studio Code # Local History for Visual Studio Code
.history/ .history/
tmp/ tmp/
uploadcache/*
spoken/*

7
Config.cs Normal file
View File

@ -0,0 +1,7 @@
using System.Collections.Generic;
public class Config
{
public string speech_service { get; set; } = "http://eligos.lan:5400";
public string sync_dropoff { get; set; } = "/home/adam/Sync/eligos documents/";
}

View File

@ -1,24 +1,185 @@
using System; using System.Collections.Concurrent;
using franz; using System.Data;
using System.Diagnostics;
namespace PlaceholderVO using System.Net;
{ using System.Reflection.Metadata.Ecma335;
internal class Program using System.Runtime.CompilerServices;
{ using System.Text;
public static Telefranz telefranz; using System.Text.RegularExpressions;
using System.Timers;
static async Task Main(string[] args) using Newtonsoft.Json;
{
Telefranz.Configure(name: "balaam placeholder VO", bootstrap_servers: "alloces:9092",
commands: ["speak"]); namespace placeholdervo
telefranz = Telefranz.Instance; {
public partial class Program
await Task.Delay(1000); {
telefranz.ProduceMessage(new gray_messages.global.sound_off());
Console.WriteLine("Hello World!"); [GeneratedRegex("^[^a-zA-Z0-9'\"]")]
private static partial Regex TextLine();
await Task.Delay(-1); public static Config conf;
private static string workingDir = "./";
}
} private static ConcurrentQueue<string> scriptFragmentFiles = new ConcurrentQueue<string>();
} 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<string[]>(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<string, string> scriptFragmentVoiceFiles = new ConcurrentDictionary<string, string>();
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<Config>(
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<string>();
var completeSavedLines = new List<string>();
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");
}
}
}

4
appsettings.json Normal file
View File

@ -0,0 +1,4 @@
{
"speech_service": "http://eligos.lan:5400",
"sync_dropoff": "/home/adam/Sync/eligos documents/"
}

View File

@ -5,11 +5,11 @@
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<RootNamespace>placeholder_VO</RootNamespace> <RootNamespace>placeholder_VO</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="greyn.franz" Version="2.1.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>